2012-07-24 98 views
2

我有以下EF代码优先代码。我收到以下例外情况:主键违例:使用EF代码优先继承

'GiftCouponPayment'不包含标识列。

表已在数据库中成功创建。但是,我怎样才能摆脱这种异常?此外,这种例外的原因是什么?

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

enter image description here

继续这个异常后,有另一个异常如下:

同时节省不为他们的关系暴露的外键的属性的实体时出错。 EntityEntries属性将返回null,因为单个实体不能被识别为异常的来源。通过在您的实体类型中公开外键属性,可以更轻松地处理保存时的异常。有关详细信息,请参阅InnerException。

{ “PRIMARY KEY约束 'PK_dbo.PaymentComponent' 违反无法插入对象 'dbo.PaymentComponent' 重复键\ r \ n该语句已终止。”}

参考

  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(); 
     } 
    } 
+0

你想要两个或三个表吗? – 2012-07-24 15:12:25

+0

如果你想要三个支付表,那么你不应该使用'MapInheritedProperties()'。 – 2012-07-26 10:32:28

+0

MapInheritedProperties用于TPC/TPH。你正在要求TPT。您需要删除MapInheritedProperties。 – 2012-07-26 10:38:37

回答

2

我看到我对TPC初步意见是不正确的,因为你也是在基类中使用FK - 你看到PaymentComponent表吗?在TPC继承的情况下,它不应该在那里。尝试使用TPT继承(从您的映射中删除MapInheritedProperties)。这将以相同的正确数据库结束。不要使用种子。 Id将由PaymentComponent表中的标识列控制(因为它现在是这样)。

+0

谢谢。我删除了MapInheritedProperties和种子设置。现在我得到例外。 “跨多个实体或关联共享的值在多个位置生成,请检查该映射是否将EntityKey分割为多个商店生成的列。”“具有相同关键字的项目已添加”。“ – Lijo 2012-07-26 13:05:00

2

在您PaymentComponent类装饰用ID KeyAttribute

[Key] 
public int PaymentComponentID { get; set; } 
+0

升级到4.3.1是一个问题吗?如果没有,我会这样做。甚至EF5.0 RC(我还没有用过那个!)。 – 2012-07-24 15:35:58

+1

有一个名为[NuGet Package Explorer](http://npe.codeplex.com/)的工具,可以让你下载VS之外的包。 – 2012-07-24 15:39:22

+0

即使使用Key属性也会出现相同的错误。 [Key]来自System。 ComponentModel。 DataAnnotations; – Lijo 2012-07-26 05:58:50

3

你没有指定为您的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() 

它允许乐观并发。

希望这会有所帮助,请告诉我,如果您需要进一步的帮助或澄清。