Pregunta

En el marco de la entidad, ¿es posible hacer que el marco inyecte el DBContext en cada objeto (entidad) que está conectado o recuperado del contexto?

Soy un tipo nhibernado y sé que es posible en NH, lo siento si es una pregunta estúpida en EF World.

Esencialmente, quiero que algunas de mis entidades tengan una propiedad de tipo dbcontext que se establecerá en la instancia del contexto por el marco en sí, cada vez que asocio la entidad con el contexto. Idealmente, tales clases se marcarán con la interfaz Marker IcontextAware o algo así.

La razón por la que quiero hacer esto es (= objetivo), quiero evitar el modelo de dominio anémico antipatrón esta vez. Pensé que si tengo ObjectContext inyectado en entidades, podrán acceder a DB, lo que me permitirá implementar consultas y las clases de dominio lógicas más complejas dentro del dominio. Si conoce otras formas de lograr mi objetivo (especialmente en el contexto de la aplicación web), haga, pero intente evitar respuestas como "No debería hacer esto porque". ¡¡¡Gracias!!!

¿Fue útil?

Solución

No debe hacer esto porque desea mantener las preocupaciones de persistencia fuera de sus objetos de dominio =)

Pero si es necesario, puede conectarse al evento ObjectMaterialized disparado por ObjectContext. En CTP5, debe lanzar su DBContext como en el constructor para su DBContext:

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

Luego implementa su función ObjectContext_OnObjectMaterialized (remitente de objeto, objectMaterializedEventargs e). A través de EventArgs, podrá acceder a su objeto, que acaba de materializarse. A partir de ahí, puede configurar la propiedad ObjectContext/DBContext de su Poco, que debe ser pública o interna.

Otros consejos

Además de acoplar su dominio a una tecnología de persistencia específica, hay otros consultas con la inyección del contexto en ese nivel. Por ejemplo, ¿cuál es la vida útil del contexto que inyectas y ese contexto siempre debería tener la misma vida para cada entidad?

Entiendo que quieres definir tus métodos comerciales en las entidades, para que puedas decir customer.MakeCustomerPreferred. Sin embargo, hay otras formas de hacer esto, sin tener que escribir la lógica comercial en ese nivel en la aplicación '. Por ejemplo, puede usar eventos comerciales. Aquí hay un ejemplo:

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

los DomainEvents la clase es una contexto ambiental Eso le permite obtener todos los manejadores para el evento de dominio específico y ejecutarlos.

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

Con esto en su lugar, puede definir sus manejadores en un nivel más alto en su arquitectura y enchufar cero, uno o más manejadores para cada evento comercial. Puede inyectar el contexto en un controlador.

Proporcionamos a nuestros clientes la opción de seguir el enfoque solicitado por el inicio del tema. Para hacer esto, incluso implementamos una solución similar (el ObjectMaterialized y otros eventos de ObjectContext y ObjectStateManager) en nuestro producto ExpressApp Framework (XAF). Esto funciona sin ningún problema en la mayoría de los escenarios, ya que las entidades tienen la misma vida que el "contexto". Esto también nos ayuda a mejorar la usabilidad para nuestros clientes que enfrentan las mismas dificultades al diseñar sus modelos de datos y la lógica comercial.

En nuestro caso, el modelo de dominio no se combina con una tecnología de persistencia específica, ya que tenemos una abstracción especial de "espacio de objetos" en el contexto ORM (además del marco de entidad, nuestro producto admite nuestros objetos persistentes de ORM internos (XPO (XPO )).

Por lo tanto, ofrecemos a nuestros clientes una interfaz IObjectSpacelink (con una sola propiedad IObjectSpace) que se supone que debe ser implementada por entidades que requieren contexto para su lógica comercial.

Además, proporcionamos una interfaz IXAFEntityObject (con los métodos de activación de información increactadas, en información realizada) para las reglas comerciales más populares. Aquí hay un ejemplo de una entidad que implementa ambas interfaces de nuestro 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() {}

A su vez, aquí está el código de nuestro marco que une estas piezas internamente (a continuación es para 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;
    }

Espero que esta información te ayude.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top