Question

Dans Entity Framework, est-il possible de rendre le cadre Injecter la DbContext dans chaque objet (entité) qui est attaché ou récupéré à partir du contexte?

Je suis un gars NHibernate et je sais qu'il est possible dans le New Hampshire, - excusez-moi si elle est une question stupide dans le monde EF

.

Pour l'essentiel, je veux certains de mes entités d'avoir une propriété de type DbContext qui se mettre à l'instance du contexte par le cadre lui-même, chaque fois que j'associe l'entité avec le contexte. Idéalement, ces classes seront marqués avec interface marqueur IContextAware ou quelque chose comme ça.

La raison pour laquelle je veux faire est (= objectif), je veux éviter anti-modèle Anemic modèle de domaine cette fois. Je me suis dit si j'ai ObjectContext injecté dans des entités, ils seront en mesure d'accéder DB, me permettant ainsi de mettre en œuvre des requêtes et des logiques plus complexes des classes à l'intérieur du domaine eux-mêmes. Si vous connaissez d'autres façons d'atteindre mon objectif (en particulier. Dans le contexte de l'application Web) s'il vous plaît faire, mais s'il vous plaît essayer d'éviter des réponses comme « vous ne devriez pas faire cela parce que ». Merci !!!

Était-ce utile?

La solution

Vous ne devriez pas faire cela parce que vous voulez garder la persistance des préoccupations sur vos objets de domaine =)

Mais si vous devez, vous pouvez brancher dans l'événement ObjectMaterialized tiré par ObjectContext. En CTP5, vous devez jeter votre DbContext comme tant dans le constructeur de votre DbContext:

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

Ensuite, votre fonction ObjectContext_OnObjectMaterialized METTRE EN ŒUVRE (expéditeur d'objet, ObjectMaterializedEventArgs e). Via les EventArgs, vous pourrez accéder à votre objet, qui vient d'être matérialisée. A partir de là, vous pouvez définir votre propriété ObjectContext / DbContext de POCO, qui doit être public ou interne.

Autres conseils

En plus de votre domaine de couplage à une technologie spécifique de persistence, il y a d'autres conserns avec l'injection du contexte à ce niveau. Par exemple, quelle est la durée de vie du contexte vous injecter et devez ce contexte ont toujours la même durée de vie pour chaque entité?

Je comprends que vous voulez définir vos méthodes commerciales sur les entités, vous pouvez donc dire customer.MakeCustomerPreferred. Il y a cependant d'autres façons de le faire, sans avoir à écrire la logique métier à ce niveau dans le application`. Par exemple, vous pouvez utiliser des événements d'affaires. Voici un exemple:

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

La classe DomainEvents est ambiante contexte qui vous permet d'obtenir tous les gestionnaires pour l'événement de domaine spécifique et les exécuter.

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

Avec cela en place, vous pouvez définir vos gestionnaires à un niveau supérieur dans votre architecture et de brancher zéro, un ou plusieurs gestionnaires pour chaque événement d'affaires. Vous pouvez injecter le contexte dans un gestionnaire.

Nous offrons à nos clients la possibilité de suivre l'approche demandée par le démarreur sujet. Pour ce faire, nous avons même mis en place une solution similaire (la ObjectMaterialized et d'autres événements de ObjectContext et ObjectStateManager) dans notre produit cadre eXpressApp (XAF). Cela fonctionne sans aucun problème dans la plupart des scénarios puisque les entités ont la même durée de vie que le « contexte ». Cela nous aide également à améliorer la facilité d'utilisation pour nos clients qui font face aux mêmes difficultés lors de la conception de leurs modèles de données et la logique métier.

Dans notre cas, le modèle de domaine n'est pas associé à une technologie de persistance spécifique, parce que nous avons une abstraction spéciale « ObjectSpace » le contexte ORM (en plus de l'Entity Framework notre produit prend en charge notre ORM en interne - eXpress persistante objets (XPO)).

Alors, nous offrons à nos clients une interface IObjectSpaceLink (avec une seule propriété de IObjectSpace) qui est censé être mis en œuvre par des entités exigeant contexte de leur logique métier.

De plus, nous fournissons une interface IXafEntityObject (avec les OnCreated, onLoaded, méthodes OnSaving) pour la plupart des règles d'affaires populaires. Voici un exemple d'une entité mise en œuvre de deux interfaces de notre 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() {}

À son tour, voici le code de notre cadre qui relie ces pièces ensemble en interne (ci-dessous est pour 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;
    }

J'espère que cette information vous aide.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top