实体框架6多对多想要插入重复的行

时间:2013-11-23 01:47:43

标签: sql entity-framework

应该不是这么难!我即将放弃EF ......

我的模特有每周报纸版。每个版本都可以有很多分类。每个分类可以出现在一个或多个版本中。我的模特:

public class Classifieds
{ 
  [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  public int ClassifiedId { get; set; }
  ...
  public virtual ICollection<EditionModel> Editions { get; set; }
}

public class EditionModel
{
  [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
  public int EditionId { get; set; } // This is YYYYWW, WW = week number
  public Date PublicationDate { get; set; }
  public virtual ICollection<Classifieds> Classifieds { get; set; }
}

OnModelCreating覆盖:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
   modelBuilder.Entity<EditionModel>()
     .Property(z => z.EditionId)
     .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

   modelBuilder.Entity<EditionModel>()
     .HasMany(c => c.Classifieds)
     .WithMany(d => d.Editions)
     .Map(x =>
     {
       x.MapLeftKey("EditionId");
       x.MapRightKey("ClassifiedId");
       x.ToTable("EditionModelClassifieds");
     });
   base.OnModelCreating(modelBuilder);
}

创建分类广告操作代码(HTTP put):

public async Task<ActionResult> Create(Classifieds classifieds, int[] EditionList)
{
  var allPubs = PopulateEditionList(); // Current and next 12 editions
  db.Set<Classifieds>().Attach(classifieds);
  db.Entry(classifieds).Collection(x => x.Editions).Load();
  foreach (var p in EditionList)
  {
      var anEd = (from x in allPubs where x.EditionId == p select x).Single();
      classifieds.Editions.Add(anEd);
  }
  ...
  if (ModelState.IsValid)
  {
     var ads = db.Classifieds.Add(classifieds);
     await db.SaveChangesAsync().ConfigureAwait(false);
     return View("Receipt", classifieds);
  }
  ...
}

在提交新的分类广告时,我得到了

Violation of PRIMARY KEY constraint 'PK_dbo.EditionModels'.  
Cannot insert duplicate key in object 'dbo.EditionModels'.

为什么EF坚持要在EditionModels中插入重复行而不是仅仅将连接表行链接到其中的现有行?我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

显然PopulateEditionList()没有将版本附加到上下文中。在foreach循环中添加此行:

db.Set<EditionModel>().Attach(anEd);

可能你可以简化整个程序。我不确定为什么要将版本加载到内存中。您可以根据足以创建关系的键创建“存根实体”。将classifieds附加到上下文似乎是多余的,因为您要将其作为新实体添加到数据库中。尝试从数据库中为DB中尚不存在的父实体加载相关版本似乎也是多余的。结果只能是一个空集合。

因此,以下更简单的版本也可以起作用:

public async Task<ActionResult> Create(Classifieds classifieds, int[] EditionList)
{
    classifieds.Editions = new List<EditionModel>();
    foreach (var p in EditionList)
    {
        var anEd = new EditionModel { EditionId = p };
        db.Set<EditionModel>().Attach(anEd);
        classifieds.Editions.Add(anEd);
    }
    //...
    if (ModelState.IsValid)
    {
        var ads = db.Classifieds.Add(classifieds);
        await db.SaveChangesAsync().ConfigureAwait(false);
        return View("Receipt", classifieds);
    }
    //...
}

答案 1 :(得分:0)

问题是EditionModel不是上下文的一部分。谢谢你,Slauma指出我正确的方向。更正的创建操作是:

...
classifieds.Editions = new List<EditionModel>();
foreach (var p in EditionList)
{
   var ed = await db.EditionModel.FindAsync(p);
   if (ed == null)
      ed = new EditionModel { EditionId = p, PublicationDate = (from q in allPubs where                       q.EditionId == p select q).Single().PublicationDate };
   InsertOrUpdate<EditionModel>(ed);
   classifieds.Editions.Add(ed);
}
...

其余代码如上所述。