Подтвердить что ты не робот

Entity Framework: как избежать столбца дискриминатора из таблицы?

У меня есть следующая таблица, созданная с использованием подхода Entity Framework Code First.

  • Как мне изменить код С#, чтобы в базе данных не был создан нежелательный столбец дискриминатора? Есть ли какие-либо атрибуты для достижения этого?
  • Как сделать имя столбца внешнего ключа "PaymentID" вместо "Payment_ PaymentID"? Есть ли какие-либо атрибуты для достижения этого?

Примечание. Версия исполнения для EntityFramework.dll 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; }

}

КЛИЕНТ

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


        }

    }
4b9b3361

Ответ 1

Наследование TPH требуется специальный столбец, который используется для идентификации типа объекта. По умолчанию этот столбец называется Discriminator и содержит имена производных объектов. Вы можете использовать Fluent-API для определения имени столбца и разных значений. Вы также можете использовать свой столбец MyType напрямую, потому что он на самом деле является дискриминатором, но в таком случае вы не можете иметь этот столбец в своей сущности (столбец может отображаться только один раз, а если вы используете его как дискриминатор, он уже рассматривается как сопоставление).

Имя столбца внешнего ключа можно снова контролировать с помощью 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"));
}

Ответ 2

Добавить атрибут [NotMapped], если свойство не будет отображаться в столбце.

Ответ 3

Также можно использовать таблицу для каждого типа (TPT).

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

Таблица для каждого типа (TPT)

Таблица для каждого типа представляет собой представление отношений наследования как реляционные ассоциации внешних ключей. Каждый класс/подкласс, который объявляет постоянные свойства, включая абстрактные классы, имеет свои собственные Таблица. Таблица для подклассов содержит столбцы только для каждого noninherited property (каждое свойство, объявленное самим подклассом) наряду с первичным ключом, который также является внешним ключом базового класса таблица.

Внедрение TPT в коде EF First

Мы можем создать сопоставление TPT, просто разместив атрибут Table на подклассы для указания отображаемого имени таблицы (атрибут таблицы - новый аннотации данных и была добавлена ​​к Пространство имен System.ComponentModel.DataAnnotations в CTP5.

Если вы предпочитаете свободный API, то вы можете создать сопоставление TPT, используя Метод ToTable():

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

Ответ 4

Поскольку вы используете подклассы, столбцу Discriminator необходимо различать каждый тип ваших подклассов.

Ответ 5

Поскольку и "GiftCouponPayment", и "ClubCardPayment" происходит от "PaymentComponent", EF не будет использовать отдельные таблицы и будет нуждаться в этом столбце. Если вам нужно другое поведение, вам придется переопределить доступ к таблице по умолчанию и сопоставить поля с вашими классами (что, я думаю, вы не хотите делать). Не уверен, что есть простой способ этого. Сначала из сущности я знаю, что есть путь через шаблон, который создает таблицы.
То же самое для имени столбца внешнего ключа. EF использует этот способ создания имени для имен ключевых/чужих ключей. Если вы хотите отформатировать таблицу по своему усмотрению, вам нужно все это сделать самостоятельно, что приводит к вопросу, почему именно использовать EF. Есть ли какая-то особая причина, почему вы хотите это сделать, кроме косметики?

Ответ 6

Пример кода для удаления столбца дискриминатора и получения столбца с именем PaymentId как дискриминатора вместо этого, поэтому решение обоих вопросов. На основе исходной документации 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));
    }
}