2009-03-29 4 views
9

Ho un'entità Foo in Entity Framework. Ma lo sto ereditando da IFoo in modo che la mia logica aziendale conosca solo IFoo - quindi estrapolando Entity Framework.Posso astrarre Entity Framework dalle mie Entità?

Il problema è che Foo ha una raccolta di entità Bar. E questa collezione è di tipo EntityCollection<Bar>.

Se inserisco questa raccolta in IFoo così com'è, eseguo IFoo in base a Entity Framework. Così ho pensato di metterlo come ICollection<IBar>, ma questo non si compila (naturalmente).

L'unica soluzione a cui riesco a pensare è di passare all'implementazione del calcestruzzo generata dal progettista di Entity Framework e modificare la raccolta da EntityCollection<Bar> a ICollection<IBar>. Ma temo il pensiero delle implicazioni che questo avrà su Entity Framework "dietro le quinte".

C'è un modo per me di definire IFoo e IBar indipendentemente Entity Framework, pur mantenendo Foo e Bar come entità EF che li implementano? Lo IFoo e lo IBar hanno senso, se non riesco a raggiungere questa indipendenza a cui tendo?

+0

Qual è il motivo esatto per cui si desidera IFoos e IBars anziché Foos e Bars? – Inferis

+0

Sto mirando alla persistenza dell'ignoranza. Vedi la risposta accettata sotto. – urig

risposta

8

Il concetto generale si fa riferimento è "la persistenza dell'ignoranza" (PI), anche se questo vale in generale direttamente ai soggetti stessi piuttosto che il codice che consuma le entità.

In ogni caso, Hibernate e NHibernate supportano nativamente PI, ma la versione iniziale di Microsoft Entity Framework non lo fa.MS ha catturato un sacco di critiche per questo e PI è probabilmente la prima caratteristica più discussa per la prossima versione (ogni volta che lo è).

Per quanto riguarda le interfacce, la raccolta di barre deve essere modificata dopo essere stata recuperata? Se la risposta è sì, non c'è una risposta facile. Anche la covarianza non può aiutarti qui perché ICollection<T> ha un metodo Add.

Se la raccolta è di sola lettura, è possibile considerare di esporla come IEnumerable<IBar>. Il metodo Enumerable.Cast lo rende abbastanza conveniente.

interface IFoo 
{ 
    IEnumerable<IBar> Bars { get; } 
} 

partial class Foo : IFoo 
{ 
    IEnumerable<IBar> IFoo.Bars 
    { 
     get { return Bars.Cast<IBar>(); } 
    } 
} 

Inoltre, so di at least one effort per rendere la versione corrente di EF supporto di persistenza ignoranza.

+0

Perché non è possibile apportare modifiche? AttachTo può collegare l'oggetto al contesto, dove possono essere apportate modifiche. – aleemb

+0

EF 4 fa questo? – BigJoe714

2

Sono uno sviluppatore Java, quindi non posso commentare con alcuna autorizzazione su Entity Framework. Posso dirvi che le soluzioni ORM come Hibernate rendono possibile avere la persistenza POJO senza dover ricorrere a classiche classi astratte, interfacce o modificare il codice byte. Gestisce relazioni come 1: me citi per il tuo Foo e Bar senza dover utilizzare classi speciali di raccolta.

La salsa speciale viene esternalizzata nella configurazione della mappatura e Hibernate stessa.

Il poco che ho letto su Entity Framework suggerisce che si tratta di una soluzione ORM con lo stesso obiettivo: persistenza POCO. Non ho visto alcuna menzione di interfacce. Non riesco a vederne il bisogno dal tuo esempio, perché è troppo astratto.

Suppongo che sia possibile ottenere quell'indipendenza tra gli oggetti di business e il livello di persistenza senza dover ricorrere a tali interfacce, perché so che Hibernate lo fa. Direi che anche la soluzione JDBC di Spring lo realizza, perché non c'è bisogno di interfacce comuni. Usano un costrutto RowMapper per traghettare i dati da una query e in un oggetto.

Vorrei poterti consigliare esattamente come farlo con Entity Framework, ma forse ti starai del cuore sapendo che si può fare.

+0

Grazie per la risposta dettagliata. Ho un'esperienza positiva in passato con NHibernate, la versione .net di Hibernate di Java. Non sono esperto di EF, ma capisco che la sua mappatura è basata su attributi piuttosto che esternalizzata in un file XML. Ecco perché ho bisogno di astrarre tramite un'interfaccia. Io penso;) – urig

+0

Forse hai ragione. Non ho visto alcuna prova di ciò in una breve analisi di un articolo di Google. Scusa, non sono più d'aiuto. – duffymo

2

Utilizzare una classe parziale per separare la logica e le regole dagli oggetti EF autogenerati. Nell'esempio seguente la classe FooEntityObject è divisa in due utilizzando la parola chiave partial. Ho usato questa tecnica prima con EF e LINQ su SQL. Le classi parziali possono essere memorizzate in file separati, quindi se rigenerate nuovamente l'oggetto EF il vostro codice personalizzato non viene sovrascritto.

interface IFoo 
{ 
    public ICollection<IBar> GetBars(); 
} 

public partial class FooEntityObject : IFoo 
{ 
    public ICollection<IBar> GetBars() 
    { 
     // convert EntityCollection<Bar> into ICollection<IBar> here 
    } 
} 


public partial class FooEntityObject 
{ 
    EntityCollection<Bar> Bars{get;set;} 
} 
2

Recentemente ho scritto un post completo su questo: Persistence Ignorance in ADO.NET Entity Framework. Potresti voler dare un'occhiata a EFPocoAdapter. Questo fa proprio questo e alla fine svanirà in EF v2.

Per quello che vale, sto usando EFPocoAdapater e funziona bene per me.

2

Abbiamo fatto esattamente la stessa cosa per LINQ to SQL. Ho risolto il problema della raccolta scrivendo una classe che include uno IList e trasmette il tipo corretto al tipo corretto. Sembra un po 'come questo:

public class ListWrapper<TSource, TTarget> : IList<TTarget> 
    where TTarget : class 
    where TSource : class, TTarget 
{ 
    private IList<TSource> internalList; 

    public ListWrapper(IList<TSource> internalList) 
    { 
     this.internalList = internalList; 
    } 

    public void Add(TTarget item) 
    { 
     internalList.Add((TSource)item); 
    } 

    public IEnumerator<TTarget> GetEnumerator() 
    { 
     return new EnumeratorWrapper<TSource, TTarget>(internalList.GetEnumerator()); 
    } 

    // and all the other IList members 
} 

EnumeratorWrapper avvolge in modo simile un IEnumerator ed esegue il casting. In LINQ to SQL classi parziali esponiamo la proprietà come questa:

public IList<ICustomer> Foos 
{ 
    get 
    { 
     return new ListWrapper<Foo, IFoo>(this.Foos_internal); 
    } 
} 

Eventuali modifiche alla lista esposta verranno eseguite sul EntitySet interna in modo da rimanere in sincronia.

Questo funziona abbastanza bene, ma la mia sensazione è che questo intero approccio è più un problema che ne vale la pena, io sono un grande fan di NHibernate e un forte sostenitore in P.I. ma abbiamo fatto un sacco di sforzi extra per farlo e non abbiamo visto alcun vantaggio. Usiamo il pattern di repository per astrarre l'effettivo accesso a DataContext che direi è la parte chiave del disaccoppiamento da LINQ a SQL.