2012-07-24 28 views
23

Tengo la siguiente tabla creada con Entity Framework Primer acercamiento del código.Entity Framework: ¿Cómo evitar la columna Discriminator de la tabla?

  1. ¿Cómo modifico el código de C# para que la columna Discriminador no deseado no se cree en la base de datos? ¿Hay algún atributo para lograr eso?
  2. ¿Cómo hacer que el nombre de la columna de la clave externa sea "PaymentID" en lugar de "Payment_ PaymentID"? ¿Hay algún atributo para lograr eso?

Nota: la versión de tiempo de ejecución para EntityFramework.dll es v4.0.30XXX

enter image description here

CÓDIGO

public abstract class PaymentComponent 
{ 
    public int PaymentComponentID { get; set; } 
    public int MyValue { get; set; } 
    public string MyType { get; set; } 
    public abstract int GetEffectiveValue(); 
} 


public partial class GiftCouponPayment : PaymentComponent 
{ 

    public override int GetEffectiveValue() 
    { 
     if (MyValue < 2000) 
     { 
      return 0; 
     } 
     return MyValue; 
    } 

} 


public partial class ClubCardPayment : PaymentComponent 
{ 
    public override int GetEffectiveValue() 
    { 
     return MyValue; 
    } 
} 

public partial class Payment 
{ 
    public int PaymentID { get; set; } 
    public List<PaymentComponent> PaymentComponents { get; set; } 
    public DateTime PayedTime { get; set; } 

} 



//System.Data.Entity.DbContext is from EntityFramework.dll 
public class NerdDinners : System.Data.Entity.DbContext 
{ 

    public NerdDinners(string connString): base(connString) 
    { 

    } 

    protected override void OnModelCreating(DbModelBuilder modelbuilder) 
    { 
     modelbuilder.Conventions.Remove<PluralizingTableNameConvention>(); 
    } 


    public DbSet<GiftCouponPayment> GiftCouponPayments { get; set; } 
    public DbSet<ClubCardPayment> ClubCardPayments { get; set; } 
    public DbSet<Payment> Payments { get; set; } 

} 

CLIENTE

static void Main(string[] args) 
    { 

     string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30"; 

     using (var db = new NerdDinners(connectionstring)) 
     { 

      GiftCouponPayment giftCouponPayment = new GiftCouponPayment(); 
      giftCouponPayment.MyValue=250; 
      giftCouponPayment.MyType = "GiftCouponPayment"; 

      ClubCardPayment clubCardPayment = new ClubCardPayment(); 
      clubCardPayment.MyValue = 5000; 
      clubCardPayment.MyType = "ClubCardPayment"; 


      List<PaymentComponent> comps = new List<PaymentComponent>(); 
      comps.Add(giftCouponPayment); 
      comps.Add(clubCardPayment); 

      var payment = new Payment { PaymentComponents = comps, PayedTime=DateTime.Now }; 
      db.Payments.Add(payment); 

      int recordsAffected = db.SaveChanges(); 


     } 

    } 
+2

Si invalida las convenciones, otros desarrolladores tendrán dificultades para entender su esquema. Es más beneficioso aprender y usar las convenciones, es decir, no tendrá que hacer preguntas al leer el código de otros desarrolladores o el código generado por defecto y tampoco tendrá que escribir código adicional. – user3285954

Respuesta

29

La herencia TPH necesita una columna especial que se usa para identificar el tipo de entidad. Por defecto, esta columna se llama Discriminator y contiene nombres de entidades derivadas. Puede usar Fluent-API para definir diferentes nombres de columnas y diferentes valores. También puede usar su columna MyType directamente porque en realidad es un discriminador, pero en tal caso no puede tener esa columna en su entidad (la columna puede correlacionarse solo una vez y si la usa como discriminador ya se considera como mapeo).

El nombre de la columna de clave externa se puede controlar de nuevo con Fluido-API:

protected override void OnModelCreating(DbModelBuilder modelbuilder) 
{ 
    modelbuilder.Conventions.Remove<PluralizingTableNameConvention>(); 

    // Example of controlling TPH iheritance: 
    modelBuilder.Entity<PaymentComponent>() 
      .Map<GiftPaymentComponent>(m => m.Requires("MyType").HasValue("G")) 
      .Map<ClubPaymentComponent>(m => m.Requires("MyType").HasValue("C")); 

    // Example of controlling Foreign key: 
    modelBuilder.Entity<Payment>() 
       .HasMany(p => p.PaymentComponents) 
       .WithRequired() 
       .Map(m => m.MapKey("PaymentId")); 
} 
1

Como está utilizando subclases, se necesita la columna Discriminador para distinguir entre cada tipo de subclases.

0

Dado que tanto "GiftCouponPayment" como "ClubCardPayment" derivan de "PaymentComponent" EF no usará tablas separadas y necesitará esa columna. Si desea un comportamiento diferente, debe anular el acceso predeterminado a la tabla y asignar los campos a sus clases (lo que creo que no desea hacer). No estoy seguro de si hay una manera fácil de hacerlo. Desde la entidad primero, sé que hay una forma de crear las tablas a través de la plantilla.
Lo mismo ocurre con el nombre de la columna de la clave externa. EF usa esa forma de crear el nombre para los nombres clave/clave extranjera. Si desea formatear la tabla como lo desee, debe hacerlo todo usted mismo, lo que lleva a la pregunta de por qué utilizar EF en absoluto.
¿Hay alguna razón en particular por la que desee hacer eso, aparte de los cosméticos?

4

podría también utilizar la tabla por Tipo (TPT).

http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-tpt

tabla por tipo (TPT)

tabla por tipo es sobre lo que representa relaciones de herencia como relacionales asociaciones de claves externas. Cada clase/subclase que declara propiedades persistentes, incluidas las clases abstractas, tiene su propia tabla .La tabla para subclases contiene columnas solo para cada propiedad no heredada (cada propiedad declarada por la subclase misma) junto con una clave principal que también es una clave externa de la clase base .

Implementar TPT en el Código EF Primera

Podemos crear una asignación TPT simplemente colocando atributo de tabla de la subclases para especificar el nombre de la tabla asignada (atributo de la tabla es una nueva anotación de datos y se ha añadido a . System.ComponentModel.DataAnnotations espacio de nombres en CTP5

Si prefiere API fluida, a continuación, puede crear una asignación TPT utilizando totable método():

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<BankAccount>().ToTable("BankAccounts"); 
    modelBuilder.Entity<CreditCard>().ToTable("CreditCards"); 
} 
+0

Tenga en cuenta que TPT no se recomienda para EF cuando el rendimiento es un problema. Consulte: https://msdn.microsoft.com/en-US/data/hh949853 en 7.1.1 –

7

Agregue el atributo [NotMapped] si la propiedad no va a asignarse a la columna.

+2

Además, agregar [NotMapped] como atributo de clase ayuda cuando no desea que EF asigne sus subclases a las tablas de la base de datos – kape123

+0

Gracias -¡usted, exactamente la respuesta que estaba buscando! – Jocie

+0

Si prefiere usar la API Fluent para esto en lugar de atributos/anotaciones, puede editar su _DbContext_ y en el método _OnModelCreating_ add: ** modelBuilder.Ignore (); ** – Rostov

0

Código de ejemplo para eliminar la columna Discriminador y obtener la columna llamada PaymentId como discriminador en su lugar, resolviendo ambas preguntas. Basado en la documentación original de Microsofts Fluent Api.

https://msdn.microsoft.com/en-us/library/jj591617%28v=vs.113%29.aspx?f=255&MSPPError=-2147217396

public enum MyEnum 
{ 
    Value1, Value2 
} 

public class MyBaseClass 

{ 
    [NotMapped] 
    public MyEnum PaymentId { get; protected set; } 
} 

public class DerivedOne: MyBaseClass 
{ 
    public DerivedOne() 
    { 
     PaymentId = MyEnum.Value1; 
    } 
} 

public class DerivedTwo: MyBaseClass 
{ 
    public DerivedTwo() 
    { 
     PaymentId = MyEnum.Value2; 
    } 
} 

public class MyDbContext : DbContext 
{ 
    DbSet<MyBaseClass> MyBaseClass { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Entity<MyBaseClass>() 
      .Map<DerivedOne>(x => x.Requires("PaymentId").HasValue((int)PaymentId.Value1)) 
      .Map<DerivedTwo>(x => x.Requires("PaymentId").HasValue((int)PaymentId.Value2)); 
    } 
} 
0

Con el fin de evitar la columna discriminadora de la mesa sólo tiene que añadir una anotación [NotMapped] por encima de su clase derivada.

Cuestiones relacionadas