2011-04-08 20 views
11

Estoy intentando usar una clase común EntityTypeConfiguration para configurar la clave primaria para todas mis entidades, de modo que cada clase de configuración derivada no se repita. Todas mis entidades implementan una interfaz común IEntity (que dice que cada entidad debe tener una propiedad Id de tipo int).Entity Framework 4.1 RC: Código First EntityTypeConfiguration inheritance issue

Mi clase de base de configuración tiene el siguiente aspecto:

public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity> 

    where TEntity : class , IEntity { 

    public EntityConfiguration() { 

     HasKey(e => e.Id); 

     Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

    } 

} 

Cada entidad a continuación, tiene su propia clase de configuración específica que se extiende ésta como esto:

public class CustomerConfiguration : EntityConfiguration<Customer> { 

    public CustomerConfiguration() : base() { 

     // Entity specific configuration here 

    } 

} 

Se compila bien, pero el problema soy teniendo es que en el tiempo de ejecución me aparece la siguiente excepción cuando EF 4.1 RC intenta crear el modelo:

System.InvalidOperationException era no administrado Mensaje = El componente clave 'Id' no es una propiedad declarada en tipo 'Cliente'. Compruebe que tiene no se ha excluido explícitamente del modelo y que es una propiedad primitiva válida . Fuente = ADO.NET Entity Framework

Si cambio de la clase CustomerConfiguration para extenderse desde EntityTypeConfiguration <cliente> y repetir la configuración de clave principal entonces funciona bien, pero pierdo la capacidad de compartir configuración común (principal DRY es la motivación).

  • ¿Estoy haciendo algo mal aquí?
  • ¿Hay alguna otra manera de compartir la configuración común entre las entidades?

Como referencia aquí son las otras clases involucradas:

public interface IEntity { 

    int Id { get; set; } 

} 

public class Customer : IEntity { 

    public virtual int Id { get; set; } 

    public virtual string name { get; set; } 

} 

Gracias!

Respuesta

2

No creo que tenga que pasar por todo esto. EF 4.1 Code First utiliza una gran cantidad de convenciones sobre la configuración y, a través de esto, la propiedad Id de una entidad se configura como la clave principal. Entonces, al implementar la interfaz IEntity en sus entidades, los configura con el Id como clave principal.

Aquí hay un enlace a la ADO.NET blog del equipo que explica cómo funciona la convención clave primaria - Conventions for Code First

+7

Sí, eso es cierto, pero personalmente no me gusta depender de las convenciones y, cuando sea posible, quiero que la configuración sea explícita, autocomprimible y bajo control de versiones. Tarde o temprano, es posible que algo no encaje dentro de las convenciones, por lo que estos problemas deberían resolverse por adelantado. También hay alguna configuración compartida que no se muestra en este ejemplo simplificado que no estoy seguro de que la convención pueda manejar automáticamente. – Jamie

+1

"No me gusta depender de las convenciones" - luego escriba una prueba y fallará cuando la convención cambie, Documentar el hecho (en código o de otro modo) es un enfoque menos que ideal – RhysC

12

Parece que estas configuraciones tiene algún problema con la interfaz. Funciona si cambia IEntity a EntityBase:

public class EntityBase 
{ 
    public virtual int Id { get; set; } 
} 

public class Customer : EntityBase 
{ 
    public virtual string Name { get; set; } 
} 

public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity> 
    where TEntity : EntityBase 
{ 
    public EntityConfiguration() 
    { 
     HasKey(e => e.Id); 
     Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
    } 
} 

public class CustomerConfiguration : EntityConfiguration<Customer> 
{ 
    public CustomerConfiguration() 
     : base() 
    { 
     ... 
    } 
} 
+0

Bueno, traté de convertir las interfaces en clases abstractas, y todavía no funciona. Luego hice que las clases base no fueran abstractas, ¡y aún no funciona! Ahora he empezado a repetir la configuración hasta que (¿algún día?) El equipo de Entity Framework admite software que usa interfaces con código primero (que yo diría que era un requisito básico). – Jamie

+0

Me funcionó con una clase base, por lo que debe haber otro problema. –

+0

Si bien esto funciona para mí, prefiero usar una interfaz. Es de esperar que EF lo respalde en el futuro. – jrummell

1

sólo podría crear un método estático de una clase y pasar a la entidad en ella. Por ejemplo:

public class CustomerConfiguration : EntityConfiguration<Customer> 
{ 
    public CustomerConfiguration() 
     : base() 
    { 
     ... 
     EntityConfiguration.Configure(this); 
    } 
} 

public static class EntityConfiguration 
{ 
    public static void Configure<TEntity>(EntityTypeConfiguration<TEntity> entity) where TEntity : EntityBase 
    { 
     entity.HasKey(e => e.Id); 
     entity.Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
    } 
} 
+0

No es una mala solución. – David

0

tengo problema similar con EF5.0 cuando tengo clase abstracta genérico con propiedad Id e implementación de los miembros abstractos y propiedades de auto definido. parece que el código de entidad de marco primero busca solo propiedades de clase mapeadas. intenté usar el reflector, parece que tengo razón, pero no estoy seguro de esto al 100%.

Y, afortunadamente, la solución, se han encontrado para esta:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     {     
      modelBuilder.Conventions.Remove<IncludeMetadataConvention>(); 
      modelBuilder.Entity<MyEntity>() 
       .Map(m => 
       { 
        **m.MapInheritedProperties();**     
       }); 
     } 

por lo que en mi caso: a mapa también propiedades de la clase base que tengo que añadir una línea de código (m.MapInheritedProperties) ...

Cuestiones relacionadas