Visual Studio 2010 EF4 新機能 Model Defined Functions (MDF)

こんにちは、部内はReMIXそしてTech·Edモードになっています。ReMIXで私は「UXコンシェルジュ」というブースでアテンド予定ですので、お時間あれば立ち寄って頂ければと思います。

今日はEF4で機能追加されるModel Defined Functions (MDF)をご紹介します。Model Defined Functions (MDF) は.NET Framework 4.0における新機能です。機能名から予測できるとおり概念モデル(CSDL)に関数を定義することができます。定義した関数にはEntity SQLやLINQ to Entitiesでアクセスすることが可能です。MDFは例えば、人の年齢計算のような共通で関数化しておくと便利なものに適用するものです。

では実際の実装方法を確認してみましょう。

関数を定義するために、CSDLに次のような<Function>要素を持つXMLを記述する必要があります。VSデザイナでedmxを作成した場合は、edmxをXMLエディターで開いて<ConceptualModels>要素の子要素である< Schema>配下の任意の場所に記述することになります。

 <Function Name ="GetAge" ReturnType="Edm.Int32">
 <Parameter Name="Employees" Type="NorthwindModel.Employees" />
 <DefiningExpression>
      Edm.DiffYears(Employees.BirthDate, Edm.CurrentDateTime())
   </DefiningExpression>
 </Function>

XMLを見ると概ね、何がしたいのかご理解頂けると思います。尚、DefiningExpressionにはEntitySQLを指定します。

詳細は下記のmsdnドキュメント(英語)をご覧ください。

Conceptual Model Functions (Entity Data Model)

上記定義を行うことで次のようにEntity SQL式からGetAge関数を呼び出すことが可能です。当然、SQL Serverなど固有のデータベースには依存しない実装になります。

 using (EntityConnection con = new EntityConnection("Name=NorthwindEntities"))
 {
 con Open. ();
 EntityCommand cmd = con.CreateCommand();
 cmd.CommandText = "SELECT VALUE p from 
                    NorthwindEntities.Employees as p
                    WHERE NorthwindModel.GetAge(p) > 60";
 EntityDataReader edr = cmd.ExecuteReader(CommandBehavior.SequentialAccess);

また、LINQ to Entitiesを用いてGetAge関数の呼び出しを行う場合、事前にStubメソッドを定義する必要があります。

 [EdmFunction("NorthwindModel", "GetAge")]
 public static int newGetAge(Employees e)
 {
 throw new NotSupportedException();
 }

ご覧のとおり、System.Data.Objects.DataClasses.EdmFunction 属性に先ほどCSDLに定義したFunction名と名前空間が設定されています。実行時にはStubがそのまま呼び出されるわけではなく、CSDLのFunctionが実行されるよう、メソッドが生成されることになります。

これで、LINQ to Entitiesを用いてMDFを呼び出すことが可能です。

 using (NorthwindEntities db = new NorthwindEntities())
 {
    var es = from e in db.Employees
           where newGetAge(e) > 60
           select e;
 }

詳細は下記のmsdnドキュメント(英語)をご覧ください。

How to: Call Model-Defined Functions in Queries (LINQ to Entities)

ちょっとパフォーマンスが心配ですが、うまく使うと便利な機能だと思います。