水平有限,歡迎指正。
原文:http://blogs.msdn.com/b/diego/archive/2012/01/10/how-to-execute-stored-procedures-sqlquery-in-the-dbcontext-api.aspx
在 Entity Framework 4.1中引入的DbContext API暴露了一些新的方法用於提供透傳原生SQL給數據庫執行查詢和命令,比如 Database.SqlQuery<T>, 以及 Database.ExecuteSqlCommand。
這些方法很重要不僅僅因為它們允許你執行自己的原生SQL查詢,而且因為它們是當前你可以使用DbContext訪問存儲過程的主要方法,特別當你使用代碼優先的開發模式。
就實現而言,它們是在EF 4.0中加入的ObjectContext.ExecuteStoreQuery<T> 和 ObjectContext.ExecuteStoreCommand 的更簡單變種。不管怎么說,關於這些方法可以做什么看上去還是會有一些困惑,尤其是它們支持的查詢語法。
簡而言之我覺得以下幾點可以說明這些方法是怎么工作的:
1、傳遞給方法的查詢文本會被設置給來自底層ADO.NET提供程序的DbCommand對象。
2、DbCommand對象是通過設置CommandType屬性值為CommandType.Text來執行的。
3、此外,如果方法會返回你之前傳遞的對象類型的結果(例如SqlQuery<T>),這個結果是基於DbDataReader返回的值所提取的。
你可以使用類似下面的語法,從一個存儲過程返回的必要列中提取一個個人實體對象:
1 var idParam = new SqlParameter { 2 ParameterName = "id", 3 Value = 1}; 4 var person = context.Database.SqlQuery<Person>( 5 "GetPerson @id", 6 idParam);
為了方便這些方法同時也接收普通的原始類型參數。你可以使用類似“{0}”的語法在查詢語句中使用這些參數。
var person = context.Database.SqlQuery<Person>( "SELECT * FROM dbo.People WHERE Id = {0}", id);
可是這些語法適用性有局限,而且可能你要做的一些事情需要更好的控制,像調用一個帶輸入輸出參數的存儲過程,或者參數不是基本類型,你必須使用數據源所支持的完整的SQL語法。
我想分享一個關於使用輸入輸出參數的簡單例子,這樣可以更好的舉例說明。
在你的SQL Server數據庫中創建一個(完整但沒什么用)存儲過程定義:
1 CREATE PROCEDURE [dbo].[GetPersonAndVoteCount] 2 ( 3 @id int, 4 @voteCount int OUTPUT 5 ) 6 AS 7 BEGIN 8 SELECT @voteCount = COUNT(*) 9 FROM dbo.Votes 10 WHERE PersonId = @id; 11 SELECT * 12 FROM dbo.People 13 WHERE Id = @id; 14 END
你可以寫一段如下所示的代碼執行它:
1 var idParam = new SqlParameter { 2 ParameterName = "id", 3 Value = 1}; 4 var votesParam = new SqlParameter { 5 ParameterName = "voteCount", 6 Value = 0, 7 Direction = ParameterDirection.Output }; 8 var results = context.Database.SqlQuery<Person>( 9 "GetPersonAndVoteCount @id, @voteCount out", 10 idParam, 11 votesParam); 12 var person = results.Single(); 13 var votes = (int)votesParam.Value;
在上面這段代碼中有幾個注意事項:
1、SqlQuery和ExecuteSqlCommand方法所支持的主要語法是被底層ADO.NET提供程序所支持的原生SQL語法。(有人在評論中提到SQL Server 2005必須在存儲過程名前面加上EXEC關鍵字)。
2、DbCommand是使用CommandType.Text(相對於CommandType.StoredProcedure)來執行的,這意味着它不會自動為存儲過程綁定參數,盡管如此你還是可以使用普通的SQL語法來執行存儲過程。
3、你必須使用正確的語法來為存儲過程傳遞一個輸入輸出參數,比如你需要在SQL語句中參數名稱的后面增加一個“OUT”關鍵字。
4、輸入和輸出參數僅僅在使用實際的DbParameters類型的時候起作用(在這個例子中我們使用SqlParameters因為我們使用SQL Server),SqlQuery和ExecuteSqlCommand所支持的普通類型對象是不支持輸入輸出參數的。(譯注:SqlQuery和ExecuteSqlCommand的參數要么全部是DbParameter參數,要么全部是普通類型對象)
5、在你訪問輸入輸出參數你必須讀整個返回結果(這個例子我們通過Single方法獲取),但這是存儲過程工作原理不是特定於EF的特性。
一旦你學會了,你可以使用提供程序特定參數和底層數據源的原生SQL語法,你能夠獲取更多和你使用ADO.NET相同的靈活性,但是使用ADO.NET無法獲得重用同一個EF所維護的數據庫連接的便利性和直接從查詢結果中獲取對象的能力。