C#と諸々

C#がメインで他もまぁ諸々なブログです
おかしなこと書いてたら指摘してくれると嬉しいです(´・∀・`)
つーかコメント欲しい(´・ω・`)

2009/05/26 13:03

こだかたろうです : New EntityFramework

不信任投票で挙がっていた点がかなり改善されそうですね。
レイジーロードがサポートされることはなおきさんから聞いていましたが、まさか PI もサポートされるとは。
気になるのは PI レベルがどのくらいなのかですね。
How to: Define Custom Persistence-Ignorant Objects (Entity Framework) を見る限り POCO は余裕でクリアしてますが、Requirements for Using Persistence-Ignorant Objects (Entity Framework) を見るとやはりいくつか制約があります。

以下、英語苦手なのできっと間違ってる所があります。(つか、自分で意味がよくわかってない所もあるので…。誰かつっこみお願いします T-T)
  • カスタムデータクラスは public でなければならない。
  • カスタムデータクラスは sealed にできない。
  • カスタムデータクラスは abstract にできない。
  • カスタムデータクラスは IEntityWithChangeTracker や IEntityWithRelationships を実装できない。
  • 概念モデル内のエンティティ型のプロパティにマッピングされた各プロパティは public でなければならない。
  • カスタムデータクラスはデフォルトコンストラクタを提供しなければならない。
  • 概念モデル内で定義されたナビゲーションプロパティは、対応するナビゲーションプロパティがカスタムデータクラスになければならない。関連オブジェクトの遅延ロードをサポートするためには、このプロパティを virtual として宣言する必要があり、sealed と宣言することはできない。
  • 一対多または多対多の関連を表すナビゲーションプロパティは、ICollection<T> (T は関連端の型) を実装する型を返さなければならない。
  • データモデル内のエンティティ型のプロパティにマッピングされたプロパティは、virtual で、getter 及び setter を実装しなければならない。
  • 概念モデル内の複合プロパティは、参照型を返すカスタムデータクラスのプロパティにマッピングしなければならない。複合プロパティを、値型や列挙型にマッピングすることはできない。
NHibernate に比べると若干 PI レベルが低そうですが、許容範囲内ですかねー。
スポンサーサイト



2008/06/19 00:54
データマッパー (PofEAA) がドメインオブジェクトをロードする際、リッチコンストラクタを用いることで最初から完成されたドメインオブジェクトを生成することができる。すると、ロードのためだけにセッターを提供したりする必要がないため、スマートなインターフェイスを実現できる。
しかし、循環参照を伴うドメインオブジェクトでは、リッチコンストラクタの使用に問題が生じる。
例えば、次の Hoge クラスと Fuga クラスのような場合だ。

class Hoge
{
    readonly Fuga _f;
    public Hoge(Fuga f)
    {
        if (f == null)
        {
            throw new ArgumentNullException("f");
        }
        this._f = f;
    }
}

class Fuga
{
    readonly Hoge _h;
    public Fuga(Hoge h)
    {
        if (h == null)
        {
            throw new ArgumentNullException("h");
        }
        this._h = h;
    }
}

Hoge のコンストラクタでは Fuga のインスタンスを必要とする。Fuga のコンストラクタでは Hoge のインスタンスを必要とする。これは通常、決してインスタンス化することができない。
しかし、.NET では、コンストラクタを呼び出さずにインスタンス化することができる。そして、リフレクションを使用すればコンストラクタを後から呼び出すこともできる。
つまり、次のようなコードでリッチコンストラクタの循環参照問題は克服できる。

// using System;
// using System.Runtime.Serialization;
// using System.Reflection;

Hoge h = (Hoge)FormatterServices.GetUninitializedObject(typeof(Hoge));
Fuga f = new Fuga(h);
ConstructorInfo ctor = typeof(Hoge).GetConstructor(new[] { typeof(Fuga) });
ctor.Invoke(h, new[] { f });

なお、コンストラクタを後から呼び出す代わりに、リフレクションで直接フィールドを設定するという方法も取れる。しかし、直接フィールドを設定する理由はないし、メリットもない。むしろ、循環参照の問題さえなければ普通にリッチコンストラクタでインスタンス化しているわけなのだから、リッチコンストラクタを使うべきだろう。