web-dev-qa-db-fra.com

Entity Framework: Comment éviter la colonne discriminante de la table?

J'ai le tableau suivant créé en utilisant Entity Framework Code First approche. 

  1. Comment modifier le code C # afin que la colonne indésirable Discriminator ne soit pas créée dans la base de données? Y at-il des attributs pour y parvenir?
  2. Comment faire en sorte que le nom de colonne de la clé étrangère soit "PaymentID" au lieu de "Payment_ PaymentID"? Y at-il des attributs pour y parvenir?

Remarque: La version d'exécution pour EntityFramework.dll est v4.0.30XXX

enter image description here

CODE

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; }

}

CLIENT

    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();


        }

    }
26
Lijo

L'héritage TPH nécessite une colonne spéciale permettant d'identifier le type d'entité. Par défaut, cette colonne s'appelle Discriminator et contient les noms des entités dérivées. Vous pouvez utiliser Fluent-API pour définir un nom de colonne et des valeurs différentes. Vous pouvez également utiliser directement votre colonne MyType car il s'agit en fait d'un discriminateur, mais dans ce cas, vous ne pouvez pas avoir cette colonne dans votre entité (la colonne ne peut être mappée qu'une seule fois et si vous l'utilisez comme discriminateur, elle est déjà considérée comme un mappage).

Le nom de la colonne de clé étrangère peut être à nouveau contrôlé avec Fluent-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"));
}
30
Ladislav Mrnka

Ajoutez un attribut [NotMapped] si la propriété ne va pas être mappée à la colonne.

8
John Li

Pourrait aussi utiliser Table par type (TPT).

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

Tableau par type (TPT)

Table par type concerne la représentation des relations d'héritage sous la forme associations de clés étrangères relationnelles. Chaque classe/sous-classe qui déclare que les propriétés persistantes, y compris les classes abstraites, ont leur propre fichier table. La table des sous-classes contient des colonnes uniquement pour chaque propriété non héritée (chaque propriété déclarée par la sous-classe elle-même) avec une clé primaire qui est également une clé étrangère de la classe de base table.

Implémenter TPT dans EF Code First

Nous pouvons créer un mappage TPT en plaçant simplement l'attribut Table sur le des sous-classes pour spécifier le nom de la table mappée (l'attribut Table est une nouvelle annotation data qui a été ajoutée à l'espace de noms System.ComponentModel.DataAnnotations dans CTP5.

Si vous préférez une API fluide, vous pouvez créer un mappage TPT en utilisant Méthode ToTable ():

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

Lorsque vous utilisez des sous-classes, la colonne Discriminator est requise pour distinguer chaque type de vos sous-classes.

1
mathieu

Etant donné que "GiftCouponPayment" et "ClubCardPayment" découlent tous deux de "PaymentComponent", EF n'utilisera pas de tableaux séparés et aura besoin de cette colonne. Si vous souhaitez un comportement différent, vous devez redéfinir l'accès par défaut à la table et mapper les champs à vos classes (ce que je ne vous prends pas, je ne le souhaite pas). Vous ne savez pas s'il existe un moyen simple d'y parvenir. D'entité d'abord, je sais qu'il existe un moyen de créer les tableaux dans le modèle. 
Il en va de même pour le nom de colonne de la clé étrangère. EF utilise cette méthode pour créer le nom des noms de clé/clé étrangère. Si vous voulez formater la table comme bon vous semble, vous devez tout faire vous-même, ce qui soulève la question de savoir pourquoi utiliser EF.
Y a-t-il une raison particulière pour laquelle vous voulez faire cela, autre que les cosmétiques?

0
DerApe

Afin d'éviter la colonne Discriminator de la table, il vous suffit d'ajouter l'annotation [NotMapped] sur votre classe dérivée.

0
Valeriy

Exemple de code pour supprimer la colonne Discriminator et obtenir la colonne nommée PaymentId comme discriminateur à la place, résolvant ainsi vos deux questions. Basé sur la documentation originale 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
Ogglas