0

在 Entity Framework 中,是否可以让框架将 DbContext 注入到每个附加到 Context 或从 Context 检索的对象(实体)中?

我是一个 NHibernate 人,我知道在 NH 中这是可能的,如果这是 EF 世界中的一个愚蠢问题,我很抱歉。

本质上,我希望我的一些实体具有 DbContext 类型的属性,每当我将实体与上下文相关联时,框架本身都会将其设置为上下文的实例。理想情况下,此类类将使用 IContextAware 标记接口或类似的东西进行标记。

我想这样做的原因是(=目标),这次我想避免贫血域模型反模式。我想如果我将 ObjectContext 注入实体,它们将能够访问 DB,从而允许我在域类本身内部实现查询和更复杂的逻辑。如果您知道实现我的目标的其他方法(尤其是在网络应用程序的上下文中),请这样做,但请尽量避免诸如“您不应该这样做,因为”之类的答案。谢谢!!!

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);
        }
    }
}

有了这个,您可以在架构中的更高级别定义处理程序,并为每个业务事件插入零个、一个或多个处理程序。您可以在处理程序中注入上下文。

于 2011-02-01T08:41:56.910 回答
0

我们为我们的客户提供了一个选项来遵循主题启动器所要求的方法。为了做到这一点,我们甚至在我们的 eXpressApp 框架 (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() {}

反过来,这里是我们框架的代码,它在内部将这些部分链接在一起(下面是实体框架 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 回答