Объект, осведомленная о объекте, в EF, чтобы избежать анемичной доменной модели

StackOverflow https://stackoverflow.com/questions/4834918

Вопрос

В рамках сущности можно ли сделать структуру вводить DBContext в каждый объект (объект), который прикреплен или извлекается из контекста?

Я парень из Nhibernate, и я знаю, что это возможно в NH, - извините, если это глупый вопрос в мире EF.

По сути, я хочу, чтобы некоторые из моих сущностей имели свойство типа DBContext, которое будет установлено в экземпляр контекста самой структурой, когда я ассоциирую объект с контекстом. В идеале такие классы будут отмечены интерфейсом маркера Icontextaware или чем -то подобным.

Причина, по которой я хочу это сделать, заключается в том, что на этот раз я хочу избежать анемичной доменной модели анти-паттерна. Я подумал, что если у меня есть объект, введенный в сущности, они смогут получить доступ к DB, что позволит мне реализовать запросы и более сложную логику сами внутри классов доменов. Если вы знаете другие способы достижения моей цели (особенно в контексте веб -приложения), пожалуйста, сделайте, но, пожалуйста, старайтесь избегать ответов, таких как «Вы не должны делать это, потому что». Спасибо!!!

Это было полезно?

Решение

Вы не должны делать этого, потому что вы хотите сохранить проблемы настойчивости от ваших объектов домена =)

Но если вам нужно, вы можете зацепить событие ObjectMaterialized, запущенное ObjectContext. В CTP5 вам нужно отменить свой DBContext, как в конструкторе для вашего DBContext:

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

Затем реализуйте свою функцию objectcontext_onobjectmaterialized (отправитель объекта, ObjectMaterializedEventargs E). Через EventArgs вы сможете получить доступ к своему объекту, который только что материализовался. Оттуда вы можете установить свойство Poco ObjectContext/DBContext, которое должно быть либо публичным, либо внутренним.

Другие советы

Помимо связывания вашего домена с конкретной технологией устойчивости, существуют другие консервы с инъекцией контекста на этом уровне. Например, в чем время жизни в контексте, который вы вводите, и должен ли этот контекст всегда иметь одинаковую жизнь для каждой сущности?

Я понимаю, что вы хотите определить свои бизнес -методы на объектах, чтобы вы могли сказать 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);
        }
    }
}

При этом вы можете определить свои обработчики на более высоком уровне в вашей архитектуре и подключить ноль, один или несколько обработчиков для каждого бизнес -мероприятия. Вы можете ввести контекст в обработчик.

Мы предоставляем нашим клиентам возможность следовать подходу, запрашиваемому стартером темы. Чтобы сделать это, мы даже реализовали аналогичное решение (объектно -учебное заведение и другие события ObjectContext и ObjectStateManager) в нашем продукте ExpressApp Framework (XAF). Это работает без каких -либо проблем в большинстве сценариев, поскольку сущности имеют такое же время жизни, что и «контекст». Это также помогает нам улучшить удобство использования для наших клиентов, которые сталкиваются с одинаковыми трудностями при разработке своих моделей данных и бизнес -логики.

В нашем случае модель домена не сочетается с конкретной технологией постоянства, потому что у нас есть специальная абстракция «объектно -пространство» в контексте ORM (в дополнение к структуре сущности наш продукт поддерживает наши внутренние ORM - экспресс -постоянные объекты (xpo )).

Итак, мы предлагаем нашим клиентам интерфейс iobjectspacelink (с одним свойством iobjectspace), который должен быть реализован организациями, требующими контекста для их бизнес -логики.

Кроме того, мы предоставляем интерфейс ixafentityObject (с помощью вспомогаемых, загруженных методов воздействия) для самых популярных бизнес -правил. Вот пример того, как сущность реализует оба интерфейса из нашего 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;
    }

Я надеюсь, что эта информация поможет вам.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top