2011-11-30 50 views
8

Me di cuenta de que Entity Framework todavía tiene muchas características "automágicas" en su última versión. Como siempre, esta es una espada verdaderamente de doble filo.¿Puedo deshabilitar las relaciones automáticas en Entity Framework Code First?

Específicamente, estoy usando el evento OnModelBuilder para crear mi modelo sobre la marcha en código usando fluentAPI (http://msdn.microsoft.com/en-us/library/hh295844(v=vs.103) .aspx). Tengo un gran conjunto de entidades y no todas cumplen con los "estándares" de Microsoft. Por ejemplo, mis columnas de ID se denominan Person_id en lugar de PersonId. Como tal, Entity no siempre detecta automáticamente la clave primaria en una tabla, o al menos, parece que no lo hace.

No me importa ser explícito cuando construyo el modelo, pero lo que sí me preocupa es que No estoy seguro de qué propiedades y relaciones Entity detectará automáticamente y cuáles ignorará o identificará erróneamente. Dado que la mayoría de mis entidades también tienen una clase parcial con métodos y propiedades auxiliares (cosas para manejar enumeraciones, etc.), temo mucho que algún día la Entidad creará automáticamente asignaciones entre cosas que no deberían mapearse (la falla podría ser Entidad o algún programador desprevenido).

¿Hay alguna manera de desactivar la función de conexión automática de Entity para que pueda ser 100% explícito en mi método OnModelBuilder? O, como mínimo, ¿cómo puedo saber cuándo necesito agregar detalles de mapeo adicionales (como la necesidad de declarar un campo opcional, o cuando una propiedad de navegación específica no será detectada automáticamente)?

Gracias!

+0

si esto te preocupa, probablemente deberías utilizar los aspectos de "diseño primero" de EF en lugar de las cosas nuevas del "código primero" –

+0

Empecé con el EDMX, por cierto. Estaba tratando de 'actualizar' al código primero pensando que podría ser más fácil de administrar, ya que todo estaría en el código, pero puede que no valga la pena el esfuerzo y la depuración del tiempo. – Brett

Respuesta

6

La auto-magia se realiza por las convenciones dentro de código de EF en primer lugar. Puede eliminar cualquiera de esos conventions para desactivar algo de magia o puede remove them all y después de eso tendrá que ser 100% explícito en su API fluida.

+0

¡Guau! Esto es exactamente lo que necesitaba! – Brett

+0

Con EF6 eliminar todas las convenciones no ayuda ... vea mi respuesta y el fragmento de código publicado al final. – baHI

0

Simplemente sea explícito sobre sus relaciones, claves y columnas en la configuración de su entidad y realmente no debería ser un problema.

Personalmente, mientras estoy codificando, lo asumo hasta que se rompe y luego corrijo la configuración.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    Database.SetInitializer<AccountWriteContext>(null); 

    modelBuilder.Configurations.Add(new AccountEntityTypeConfiguration()); 
    modelBuilder.Configurations.Add(new AccountOwnerEntityTypeConfiguration()); 
    modelBuilder.Configurations.Add(new CreditCardEntityTypeConfiguration()); 
    modelBuilder.Configurations.Add(new TenantEntityTypeConfiguration()); 
    //blah blah blah 
} 


class AccountOwnerEntityTypeConfiguration 
    : EntityTypeConfiguration<AccountOwner> 
{ 
    public AccountOwnerEntityTypeConfiguration() 
    { 
     this.HasKey(p => p.ID); 
     this.Property(p => p.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired(); 

     this.HasRequired(o => o.CreditCard).WithMany().HasForeignKey(c => c.CreditCardID).WillCascadeOnDelete(true); 

     this.ToTable("AccountOwner", "AccountWrite"); 
    } 
} 
+0

Esto nunca funcionó como está escrito. Incluso en ese ejemplo exacto, si tuviera que acceder a la entidad AccountOwner y agregar una propiedad, EF agregaría automágicamente la propiedad en la próxima migración, incluso si no la agrego en EntityTypeConfiguration. – Suamere

+0

en 2011 lo hizo. – William

-2

Recomendaría utilizar los Atributos de la anotación de datos para hacerlo. Por ejemplo, el atributo [key] se puede usar para definir su clave principal y el atributo [table] se puede usar para proporcionar el nombre de su tabla. El atributo [required] se puede usar para decirle a EF que se necesita un campo.

En mi opinión, es mucho más fácil usar la sintaxis de atributo que usar la sintaxis para actualizar el modelo, y también es autodocumentado, ya que los atributos se colocan directamente en el código del objeto.

Para obtener más información, consulte esta entrada del blog que muestra todos los atributos disponibles:

http://blogs.msdn.com/b/efdesign/archive/2010/03/30/data-annotations-in-the-entity-framework-and-code-first.aspx

+0

La pregunta era "cómo deshabilitar". Y asumo sin decir explícitamente qué columnas deshabilitar. Es irrelevante si prefiere anotaciones o sintaxis fluida. El objetivo es tener un mapeo estable, sin la necesidad de decirle explícitamente que ignore las nuevas propiedades ... – baHI

0

En realidad este código elimina todas las convenciones, incluso despeja el conjunto inicial ...

... pero aún se asignan las columnas que no se asignaron con EntityTypeConfiguration ...

private void RemoveAllConventions(DbModelBuilder modelBuilder) 
     { 
      new List<string>() 
      { 
      "_configurationConventions", 
      "_conceptualModelConventions", 
      "_conceptualToStoreMappingConventions", 
      "_storeModelConventions" 
      } 
      .ForEach(field => 
      { 
       var values = 
        (IEnumerable<IConvention>)typeof(ConventionsConfiguration) 
         .GetField(field, BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic) 
         .GetValue(modelBuilder.Conventions); 

       modelBuilder.Conventions.Remove(values.ToArray()); 
      }); 

      var initialCS = typeof(ConventionsConfiguration) 
         .GetField("_initialConventionSet", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic) 
         .GetValue(modelBuilder.Conventions); 

      new List<string>() 
      { 
      "ConfigurationConventions", 
      "ConceptualModelConventions", 
      "ConceptualToStoreMappingConventions", 
      "StoreModelConventions" 
      } 
      .ForEach(field => 
      { 
       var values = 
        (IEnumerable<IConvention>) initialCS 
         .GetType() 
         .GetProperty(field, BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public) 
         .GetValue(initialCS); 

       modelBuilder.Conventions.Remove(values.ToArray()); 
      }); 


     } 
+1

No está claro si el código publicado responde la pregunta. ¿Es este tu estado actual de cosas, pero todavía no funciona? ¿O esto resuelve el problema, pero conduce a otras preguntas? – Tunaki

1

Ok, ya que la eliminación de las convenciones no funciona, hay una manera simple de no asignar todas las propiedades no configuradas dentro de EF6.x

Lo básico es usar clases de mapeo separadas, y después de hacer los mapas manuales dentro de una clase, simplemente llame a un método, que con la reflexión obligará a ignorar todas las propiedades que no fueron configuradas.

Aquí hay un enlace a mi idea, donde está la implementación. También se agregó una muestra como comentario: https://gist.github.com/hidegh/36d92380c720804dee043fde8a863ecb

+0

Esto debería funcionar para todas las propiedades, por lo que también para colecciones (1: n) u otras referencias (n: 1) – baHI

Cuestiones relacionadas