Entity Framework4.1をWCF RIA Servicesで使う手順はこれで良いかな

久々のブログ(ブログというか月報になっとるけど)。

WCF RIA Servicesを使おうかと考えているシステムがあって、じゃあどうせならEntity Frameworkも最新の4.1を使いたいなあと思ったんだけど、これがちょっと難儀した。
EF4.0だったら項目の追加からドメインサービスを追加したら大体あんじょうよろしくやってくれるんだけど、4.1は新しいせいかいろいろと手作業しなければならない感じだった。

忘れないように手順を残しておこうと思うのと、調べ足りないだけでもっと良い方法がある場合は指摘してもらえると有り難いなあと思ってEntity Framework4.1 を WCF RIA Services で使う手順を書きます。
今回はデータベースファーストでやりましたが、コードファーストでもだいたい同じです。

1.まずはプロジェクト作成

ふつうのSilverlightアプリケーションプロジェクトを作成します。
RIA サービスは有効に。

2.NuGetでRIAServices.EntityFrameworkをゲット

NuGet Galleryはこちら
http://nuget.org/List/Packages/RIAServices.EntityFramework

3.データモデルを作成

EntityFramewok4.0と同じ手順でデータモデルを作成します。
今回はデータベースファースト

至極シンプルなデータベース・・・

データはこんな感じ

4.ドメインサービスクラスを追加

ドメインサービスクラスを追加します。

この段階ではEF4.1はまだ使われていません。EF4.0用のドメインサービスクラスが出来上がります。

5.DbContext Generatorを使ってEF4.1用のEntityクラスを生成

データモデルのデザイナ上で右クリックして、「コード生成項目の追加」を選択します。

コードジェネレーターの選択ダイアログが出るので、オンラインテンプレートの「ADO.NET C# DbContext Generator」を選択します。

こでれ、EntityクラスがEF4.1を使用したものになると同時に、ドメインサービスクラスが4.1に対応していないためビルドエラーとなります。

6.ドメインサービスクラスをEF4.1用に修正

現段階だとビルドが通らないので、4で追加したドメインサービスクラスをEF4.1用に書き換えます。

コード例 (今回の例はGetだけ。更新系はまた別の機会にやろうと思います。)

   [EnableClientAccess()]
    public class SampleService : DbDomainService<SampleDBEntities>
    {
        public IQueryable<Country> GetCountries()
        {
            return this.DbContext.Countries;
        }

        public IQueryable<Driver> GetDrivers()
        {
            return this.DbContext.Drivers.Include("Countries");
        }
    }

ポイントは3つ。

    • LinqToEntitiesDomainServiceではなくDbDomainServiceクラスを継承させる。
    • ObjectContextではなくDbContextを使う。
    • 関連エンティティを取得するためにInclude()メソッドを使う。

7.Entityクラス生成テンプレートを修正する

関連エンティティを取得するためにEntityクラスのナビゲーションプロパティに[Include]属性をつけます。
テンプレートで自動生成されるクラスなので、テンプレート(ttファイル)の方を修正します。
下記2カ所です。

  • 197行目くらいの名前空間を書き込むところに下記を追加
using System.ServiceModel.DomainServices.Server;
  • 237行目くらいのWriteNavigationPropertyメソッドの最初に下記を追加
#>
	[Include]
<#+

そうすると自動生成されたクラスがこんな感じになります。

ちゃんと[Include]属性が付いてます。
これで、サーバー側の作業は終わりです。(ふぅ・・・)

8.クライアント側からの利用方法

クライアント用のDomainContextを生成して、Loadメソッドを使って取得します。
画面とかの細かいことは下の方にサンプルソースのリンクを張りますのでそちらを見てください。

    //サービスに対応するDomainContextを生成します。
    var context = new SampleContext();

    //Driversを取得します。
    context.Load(
        context.GetDriversQuery(),
        loadOperation => 
        {
            Drivers = new ObservableCollection<Driver>(loadOperation.Entities);
        },
        null);

はい、ちゃんとCountriesエンティティのCountryName(国名)も取得できているようです。

9.まとめ

とりあえず、このやり方でEntity Framework4.1でWCF RIA Servicesが使えそう。
ただ、実はもっと簡単なやり方があるんじゃないかと思ったりもする。みんなどうやってるんだろう・・・。

とりあえずドメインサービスクラスのテンプレートがEF4.1対応してくれたらなあと思う。
来年あたりになればこんなことしなくて良いようになるんだろうけど。

「実はこの設定でやればできるよ」
とかいうのが最近多いので、探し切れていない可能性も。
もしもっと簡単なやり方ご存じの方、教えてください・・・。

とここまで書いたところでこの記事を発見
WCF RIA Services Support for EF 4.1 (and EF Code-First) « varunpuranik

Again, the SP2 release bits will have full wizard support for DbContext. So you should not need to do any of this dance with the code snippet. But till then, this should be easy enough for you to do.

やっぱSP2で対応なのよねん。寿命の短い記事になりそうです・・・

あ、サンプルソースはこちらです。(SQL CE4.0使用)
http://ef41riaservicessampl.codeplex.com/SourceControl/changeset/changes/10399