c# - 主键冲突 : Inheritance using EF Code First

标签 c# .net entity-framework ef-code-first

我有以下 EF 代码优先代码。我收到以下异常:

'GiftCouponPayment' does not contain an identity column.

数据库中的表已成功创建。但是,我怎样才能摆脱这个异常(exception)呢?另外,这个异常的原因是什么?

注意:只要保留域模型(首先使用代码描述)(并且可以查询数据),我可以接受任何表模式。

enter image description here

继续此异常后,又出现如下异常:

An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.

{"Violation of PRIMARY KEY constraint 'PK_dbo.PaymentComponent'. Cannot insert duplicate key in object 'dbo.PaymentComponent'.\r\nThe statement has been terminated."}

引用:

  1. Entity Framework: Split table into multiple tables

注意:生成的数据库架构如下所示。

enter image description here

代码:

public class MyInitializer : CreateDatabaseIfNotExists<NerdDinners>
{
    //Only one identity column can be created per table.
    protected override void Seed(NerdDinners context)
    {
        //context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX IX_Payment_PayedTime ON Payment (PayedTime)");
        context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('Payment', RESEED, 1)");
        context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('GiftCouponPayment', RESEED, 2)");
        context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('ClubCardPayment', RESEED, 3)");
    }
}

//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)
    {
        //Fluent API - Plural Removal
        modelbuilder.Conventions.Remove<PluralizingTableNameConvention>();

        //Fluent API - Table per Concrete Type (TPC)
        modelbuilder.Entity<GiftCouponPayment>()
            .Map(m =>
            {
                m.MapInheritedProperties();
                m.ToTable("GiftCouponPayment");
            });

        modelbuilder.Entity<ClubCardPayment>()
            .Map(m =>
            {
                m.MapInheritedProperties();
                m.ToTable("ClubCardPayment");
            });
    }

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

public abstract class PaymentComponent
{
    public int PaymentComponentID { get; set; }
    public int MyValue { 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; }
}

客户:

    static void Main(string[] args)
    {
        Database.SetInitializer<NerdDinners>(new MyInitializer());
        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;
            
            ClubCardPayment clubCardPayment = new ClubCardPayment();
            clubCardPayment.MyValue = 5000;
                    
            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();
        }
    }

最佳答案

您没有为 TPC/TPT 映射指定 ID 字段。即使使用继承,您也需要在不运行 TPH 映射时执行此操作。 (请注意,我也不确定 MapInheritedProperties() 调用...这通常用于 TPH...而不是 TPT)

 //Fluent API - Table per Concrete Type (TPC)
 modelbuilder.Entity<GiftCouponPayment>()
      .HasKey(x => x.PaymentComponentID)
      .Map(m =>
      {
          m.MapInheritedProperties();
          m.ToTable("GiftCouponPayment");
      })
      .Property(x => x.PaymentComponentID)
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

这需要在具体类型的每个类映射上。如果是我,我会使用 TPH 映射,其中 GiftCoupon 以及其他继承映射,这样您最终会得到一个表来表示使用鉴别器列的整个对象树。

无论如何...您在基类中缺少的另一件事是:

public byte[] Version { get; set; }

以及相关的映射:

Property(x => x.Version).IsConcurrencyToken()

允许乐观并发。

希望这对您有所帮助,如果您需要进一步的帮助或说明,请告诉我。

关于c# - 主键冲突 : Inheritance using EF Code First,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11632951/

相关文章:

c# - Entity Framework Include() 返回 null 导航属性

c# - WCF 层

C# Hashtable 不保留值

c# - C++ CLI 句柄类型

.net - 可枚举的先决条件

C# EF 将记录添加到客户表,其中包含 Zip 表的外键

c# - 我有一个现有的接口(interface)(带有属性)什么是隔离读写的最佳方法

.net - 查找另一个地理点范围内的地理点 - SQL Server

c# - 具有空选择的 SelectList

wcf - Async=true 和 Entity Framework