Entity Framework - 在EF中使用User Defined Function(UDF)
PS:這篇文章的作法算是一種變通方式,未來如有更好的方法會繼續更新.
UDF功能是MS-SQL上常用的功能,但因為UDF是使用者自行定義的,想當然SQL Provider並不會認得,所以EF更不可能會知道有哪些UDF.
故在EF中必須手動建立EF與UDF間的關係,跟上一篇Entity Framework - Model-Defined Functions大致上相同,請先看過
這篇文章後再繼續閱讀,UDF跟上篇文章的差異點在於Model-Defined Functions中的SQL語法並不能直接使用UDF,因為
Provider無法直接轉譯,故須做些調整,
跟上篇文章不同之處有二
1.Model-Defined Functions的定義是在Conceptual Model,而UDF需定義在Storage Model.
而設定的就如同EF設計stored procedure一樣,只是在一些參數上有所不同,但不幸的VS內建的EDM tools只能設計stored procedure
而無法定義UDF,所以請依上篇文章做法手動用XML Editor開啟EDM File.開啟後在<edmx:StorageModels>區段後加上
<Function Name="MYGETYEAR" ReturnType="int" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
<Parameter Name="time" Type="datetime" Mode="In" />
</Function>
這邊的XML跟上篇文章很像,差異點在於UDF是定義於Storage Model故所有的資料型別都是sql type,這邊就不再多加說明了,紅字以外的描述都直接套用即可.
2.修改完 EDM後一樣的如同Model-Defined Functions上篇文章中的步驟二也必須在程式端定義一個類別來供給LINQ套用唯一的差別在於EdmFunctionAttribute的第一個參數namespace
改為EDM Storage Model區段中的namespace,可以在<edmx:StorageModels>後的<Schema Namespace="TestModel.Store" ../>取得
故在程式最後修改如下
public static class MySQLFunction
{
[EdmFunction("TestModel.Store", "MYGETYEAR")]
public static int MYGETYEAR(DateTime time)
{
throw new NotSupportedException("Direct calls are not supported.");
}
而使用端就可以透過MySQLFunction.MYGETYEAR()來使用
using (TestEntities dc = new TestEntities())
{
var q = dc.tb_Person.Select(p => new { SQLDate = MySQLFunction.MYGETYEAR(p.CreateTime) });
Console.WriteLine(((ObjectQuery)q).ToTraceString());
}
最後輸出的結果如下
畫面上可以看到MySQLFunction.MYGETYEAR()已正確的轉成對應的UDF.