Entity Framework - 在EF中使用User Defined Function(UDF)

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());
            }

最後輸出的結果如下

image

畫面上可以看到MySQLFunction.MYGETYEAR()已正確的轉成對應的UDF.