最近項目用到EF,雖然說EF與Linq To SQL有很多地方相似,但是EF(這裡指3.5版,4.0版的還沒去留意)確實有些地方做得不夠方便。
就拿存儲過程來說吧,EF裡面想調用存儲過程不是直接在數據庫裡拖進來就可以用,還要做一個function import的步驟來建立映射。 如果你的存儲過程返回的是一個select * from .....的語句的話,那恭喜你,你的存儲過程可以直接使用了。但是如果你的存儲過程是返回標量值的呢?那不行,你會發現你的代碼提示裡面還是沒有出現想要的存儲過程名稱。
為什麼呢?原因就是EF沒有為返回標量值的存儲過程自動生成cs代碼,他只是在edmx文件裡面寫上了諸如
<Function Name="GetOrder" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
<Parameter Name="OrderID" Type="int" Mode="In" />
</Function>
這樣一串映射配置。如需在EF中調用這種存儲過程的話,就必須自己寫一個通用的調用方法,以下是方法的代碼:
private T ExecuteFunction<T>(string functionName, System.Data.EntityClient.EntityParameter[] parameters) where T : struct
{
System.Data.EntityClient.EntityCommand cmd = ((System.Data.EntityClient.EntityConnection)this.Connection).CreateCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddRange(parameters);
cmd.CommandText = this.DefaultContainerName + "." + functionName;
try
{
if (cmd.Connection.State != System.Data.ConnectionState.Open)
cmd.Connection.Open();
var obj = cmd.ExecuteScalar();
return (T)obj;
}
catch (System.Exception)
{
throw;
}
finally
{
cmd.Connection.Close();
}
}
其中泛型T就是你的存儲過程返回值的類型。
雖然說有了調用方法,但是你還不可以放松,注意到方法裡面有這樣一句 var obj = cmd.ExecuteScalar();這句的意思就是獲取返回表格的第一行數據,這有什麼問題呢?問題就在於他只能拿到形式為表格(table)的返回值,如果你的存儲過程是用return來返回結果的話,那不好意思,上面的方法會拋出一個The data reader returned by the store data provider does not have enough columns for the query requested.的異常,原因是return的存儲過程並沒有返回表格。這樣的話,我們必須還要修改一下存儲過程,把return改成select,這樣就能順利調用了。