2009-03-29 20 views
9

Tengo una entidad Foo en Entity Framework. Pero lo hago heredar de IFoo para que mi lógica de negocio solo conozca IFoo - abstrayendo así Entity Framework.¿Puedo abstraer Entity Framework de mis Entidades?

El problema es que Foo tiene una colección de Bar entidades. Y esta colección es del tipo EntityCollection<Bar>.

Si pongo esta colección en IFoo como está, hago que IFoo dependa de Entity Framework. Así que pensé en ponerlo como ICollection<IBar>, pero esto no se compila (naturalmente).

La única solución que se me ocurre es ir a lo concreto Foo aplicación generada por el diseñador de Entity Framework y cambiar a obtenerse de EntityCollection<Bar> a ICollection<IBar> allí. Pero me da miedo la idea de las implicaciones que esto tendrá en Entity Framework "detrás de escena".

¿Hay alguna forma para mí y para definir IFooIBar independientemente del marco de la entidad, manteniendo Foo y Bar como entidades EF que las aplican? ¿Tienen sentido IFoo y IBar, si no puedo lograr esta independencia a la que aspiro?

+0

¿Cuál es la razón exacta por la que desea IFoos e IBars en lugar de Foos and Bars? – Inferis

+0

Mi objetivo es la ignorancia de la persistencia. Ver la respuesta aceptada a continuación. – urig

Respuesta

8

El concepto general que usted se refiere es "ignorancia de la persistencia" (PI), aunque por lo general se aplica directamente a las entidades a sí mismos en lugar del código que consume las entidades.

En cualquier caso, Hibernate y NHibernate admiten nativamente PI, pero la versión inicial de Entity Framework de Microsoft no.MS detectó muchos errores y PI es probablemente la función más discutida en la próxima versión (siempre que sea).

En cuanto a lo que está tratando de hacer con las interfaces, ¿la colección de barras debe modificarse después de que se recupera? Si la respuesta es sí, no hay una respuesta fácil. Incluso la covarianza no pudo ayudarlo aquí porque ICollection<T> tiene un método Agregar.

Si la colección es de solo lectura, puede considerar exponerla como IEnumerable<IBar>. El método Enumerable.Cast lo hace bastante conveniente.

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

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

Además, sé de at least one effort para hacer la versión actual de EF ignorancia apoyo persistencia.

+0

¿Por qué no se pueden hacer modificaciones? AttachTo podría adjuntar el objeto al contexto, donde se pueden realizar modificaciones. – aleemb

+0

¿EF 4 hace esto? – BigJoe714

2

Soy desarrollador de Java, por lo que no puedo comentar con ninguna autoridad sobre Entity Framework. Puedo decirles que las soluciones ORM como Hibernate hacen posible la persistencia de POJO sin tener que recurrir a clases abstractas comunes, interfaces o modificación de código de bytes. Maneja relaciones como la 1: m que citas para tu Foo y Bar sin tener que usar clases de colección especiales.

La salsa especial se externaliza en la configuración de mapeo e Hibernate.

Lo poco que leí sobre Entity Framework sugiere que es una solución ORM con el mismo objetivo: persistencia de POCO. No vi ninguna mención de interfaces. No puedo ver la necesidad de su ejemplo, porque es demasiado abstracto.

Estoy deduciendo que es posible obtener esa independencia entre los objetos de negocio y el nivel de persistencia sin tener que recurrir a esas interfaces, porque sé que Hibernate lo hace. Yo diría que la solución JDBC de Spring lo logra también, porque no hay necesidad de interfaces comunes. Usan una construcción RowMapper para transportar los datos de una consulta a un objeto.

Ojalá pudiera aconsejarle con precisión cómo hacerlo con Entity Framework, pero tal vez se desanime sabiendo que se puede hacer.

+0

Gracias por la respuesta detallada. Tengo una experiencia positiva en el pasado con NHibernate, la versión .net de Hibernate de Java. No soy experto en EF, pero entiendo que su asignación se basa en atributos en lugar de en un archivo XML. Es por eso que necesito abstraer a través de una interfaz. Pienso;) – urig

+0

Quizás tienes razón. Simplemente no vi ninguna evidencia de eso en un breve repaso de un artículo de Google. Lo siento, no soy más útil. – duffymo

2

Utilice una clase parcial para separar su lógica y reglas de los objetos EF autogenerados. En el ejemplo siguiente, la clase FooEntityObject se divide en dos utilizando la palabra clave parcial. He usado esta técnica antes con EF y LINQ to SQL. Las clases parciales se pueden almacenar en archivos separados, por lo que si vuelve a generar su objeto EF, su código personalizado no se sobreescribirá.

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

Recientemente escribí una publicación exhaustiva sobre esto: Persistence Ignorance in ADO.NET Entity Framework. Es posible que desee ver EFPocoAdapter. Eso hace exactamente esto y eventualmente se depreciará en EF v2.

Por lo que vale, estoy usando EFPocoAdapater y me ha estado funcionando bien.

2

Hemos estado haciendo exactamente lo mismo para LINQ to SQL. Solucioné el problema de la recopilación escribiendo una clase que incluye un IList y arroja desde y hacia el tipo correcto según sea necesario. Se ve un poco como esto:

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 envuelve de manera similar un IEnumerator y realiza la fundición. En el LINQ a SQL clases parciales exponemos la propiedad como esta:

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

Cualquier cambio en la lista expuesta se llevarán a cabo en el EntitySet interna para que se mantengan en sincronía.

Esto funciona bastante bien, pero mi sensación es que todo este enfoque es más problemático de lo que vale, soy un gran admirador de NHibernate y un gran defensor de P.I. pero hemos puesto MUCHO esfuerzo extra haciendo esto y realmente no hemos visto ninguna ventaja. Usamos el patrón de repositorio para abstraer el acceso real de DataContext, que diría que es la parte clave para desacoplarnos de LINQ a SQL.

Cuestiones relacionadas