0

Entity Frameworkでは、フレームワークにDbContextを、コンテキストにアタッチされている、またはコンテキストから取得されている各オブジェクト(エンティティ)に挿入することはできますか?

私はNHibernateの人で、NHでも可能だと知っています。EFの世界でばかげた質問だとすみません。

基本的に、エンティティをコンテキストに関連付けるたびに、フレームワーク自体によってコンテキストのインスタンスに設定されるDbContextタイプのプロパティをエンティティの一部に持たせたいと思います。理想的には、そのようなクラスはIContextAwareマーカーインターフェイスなどでマークされます。

私がこれをやりたい理由は(=目標)です。今回は貧血ドメインモデルのアンチパターンを避けたいと思います。ObjectContextをエンティティに注入すると、DBにアクセスできるようになり、ドメインクラス自体の内部にクエリやより複雑なロジックを実装できるようになると思いました。私の目標を達成するための他の方法を知っている場合(特にWebアプリのコンテキストで)、そうしてください。ただし、「これを行うべきではない」などの回答は避けてください。ありがとう!!!

4

3 に答える 3

2

ドメインオブジェクトから永続性の懸念を排除したいので、これを行うべきではありません=)

ただし、必要な場合は、ObjectContextによって発生するObjectMaterializedイベントにフックできます。CTP5では、DbContextのコンストラクターでDbContextを次のようにキャストする必要があります。

((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += 
    this.ObjectContext_OnObjectMaterialized;

次に、関数ObjectContext_OnObjectMaterialized(object sender、ObjectMaterializedEventArgs e)を実装します。EventArgsを介して、マテリアライズされたばかりのオブジェクトにアクセスできるようになります。そこから、POCOのObjectContext / DbContextプロパティを設定できます。これは、パブリックまたは内部のいずれかである必要があります。

于 2011-01-29T04:20:10.497 に答える
1

ドメインを特定の永続化テクノロジーに結合することに加えて、そのレベルでコンテキストを注入することに関する他の懸念があります。たとえば、注入するコンテキストの存続期間はどのくらいですか。そのコンテキストは、エンティティごとに常に同じ存続期間を持つ必要がありますか?

エンティティでビジネスメソッドを定義したいので、と言うことができますcustomer.MakeCustomerPreferred。ただし、アプリケーションでそのレベルのビジネスロジックを記述しなくても、これを行う方法は他にもあります。たとえば、ビジネスイベントを使用できます。次に例を示します。

public class Customer
{
    public void MakeCustomerPreferred()
    {
        var e = new MakeCustomerPreferredEvent()
        {
            Customer = this
        };

        DomainEvents.Current.Handle(e);
    }
}

public interface IDomainEvent { }

public interface IHandle<T> where T : IDomainEvent
{
    void Handle(T instance);
}

public class MakeCustomerPreferredEvent : IDomainEvent
{
    prop Customer Customer { get; set; }
}

このDomainEventsクラスは、特定のドメインイベントのすべてのハンドラーを取得して実行できるようにするアンビエントコンテキストです。

public class DomainEvents
{
    public static DomainEvents Current = new DomainEvents();

    public virtual void Handle<T>(T instance) 
        where T : IDomainEvent
    {
        var handlers =
           YourIocContainer.GetAllInstances<IHandle<T>>();

        foreach (var handler in handlers)
        {
            handler.Handle(instance);
        }
    }
}

これを適切に配置すると、アーキテクチャの上位レベルでハンドラーを定義し、ビジネスイベントごとに0、1、または複数のハンドラーをプラグインできます。ハンドラーにコンテキストを挿入できます。

于 2011-02-01T08:41:56.910 に答える
0

トピックスターターが要求するアプローチに従うオプションをクライアントに提供します。これを行うために、eXpressApp Framework(XAF)製品に同様のソリューション(ObjectMaterializedおよびObjectContextとObjectStateManagerの他のイベント)を実装しました。エンティティの存続期間は「コンテキスト」と同じであるため、これはほとんどのシナリオで問題なく機能します。これは、データモデルとビジネスロジックを設計するときに同じ問題に直面しているクライアントの使いやすさを向上させるのにも役立ちます。

私たちの場合、ドメインモデルは特定の永続化テクノロジーと結合されていません。これは、ORMコンテキストに特別な「ObjectSpace」抽象化があるためです(エンティティフレームワークに加えて、当社の製品は社内のORMをサポートしています-eXpress Persistent Objects(XPO ))。

そのため、ビジネスロジックのコンテキストを必要とするエンティティによって実装されることになっているIObjectSpaceLinkインターフェイス(単一のIObjectSpaceプロパティを使用)をクライアントに提供します。

さらに、最も一般的なビジネスルール用のIXafEntityObjectインターフェイス(OnCreated、OnLoaded、OnSavingメソッドを使用)を提供します。BCLから両方のインターフェースを実装するエンティティの例を次に示します。

        // IObjectSpaceLink
    IObjectSpace IObjectSpaceLink.ObjectSpace {
        get { return objectSpace; }
        set { objectSpace = value; }
    }

    // IXafEntityObject
    void IXafEntityObject.OnCreated() {
        KpiInstance kpiInstance = (KpiInstance)objectSpace.CreateObject(typeof(KpiInstance));
        kpiInstance.KpiDefinition = this;
        KpiInstances.Add(kpiInstance);
        Range = DevExpress.ExpressApp.Kpi.DateRangeRepository.FindRange("Now");
        RangeToCompare = DevExpress.ExpressApp.Kpi.DateRangeRepository.FindRange("Now");
    }
    void IXafEntityObject.OnSaving() {}
    void IXafEntityObject.OnLoaded() {}

次に、これらの部分を内部でリンクするフレームワークのコードを次に示します(以下はEntity Framework 6用です)。

        private void ObjectContext_SavingChanges(Object sender, EventArgs e) {
        IList modifiedObjects = GetModifiedObjects();
        foreach(Object obj in modifiedObjects) {
            if(obj is IXafEntityObject) {
                ((IXafEntityObject)obj).OnSaving();
            }
        }
    }
    private void ObjectContext_ObjectMaterialized(Object sender, ObjectMaterializedEventArgs e) {
        if(e.Entity is IXafEntityObject) {
            ((IXafEntityObject)e.Entity).OnLoaded();
        }
    }
    private void ObjectStateManager_ObjectStateManagerChanged(Object sender, CollectionChangeEventArgs e) {
        if(e.Action == CollectionChangeAction.Add) {
            if(e.Element is INotifyPropertyChanged) {
                ((INotifyPropertyChanged)e.Element).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);
            }
            if(e.Element is IObjectSpaceLink) {
                ((IObjectSpaceLink)e.Element).ObjectSpace = this;
            }
        }
        else if(e.Action == CollectionChangeAction.Remove) {
            if(e.Element is INotifyPropertyChanged) {
                ((INotifyPropertyChanged)e.Element).PropertyChanged -= new PropertyChangedEventHandler(Object_PropertyChanged);
            }
            if(e.Element is IObjectSpaceLink) {
                ((IObjectSpaceLink)e.Element).ObjectSpace = null;
            }
        }
        OnObjectStateManagerChanged(e);
    }
    public virtual Object CreateObject(Type type) {
        Guard.ArgumentNotNull(type, "type");
        CheckIsDisposed();
        Object obj = CreateObjectCore(type);
        if(obj is IXafEntityObject) {
            ((IXafEntityObject)obj).OnCreated();
        }
        SetModified(obj);
        return obj;
    }

この情報がお役に立てば幸いです。

于 2015-01-27T19:53:13.933 に答える