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

时间:2022-10-05 16:49:41

It shouldn't be this hard! I am about to give up on EF...

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

My model has weekly newspaper Editions. Each Edition can have many Classifieds. Each Classified can appear in one or more Editions. My models:

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

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

The OnModelCreating override:

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

The Create Classifieds Action code (HTTP put):

Create Classifieds Action代码(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);
  }
  ...
}

On submit of a new Classifieds, I get

在提交新的分类广告时,我明白了

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

Why does EF insist on wanting insert duplicate rows in EditionModels instead of just linking the junction table row to an existing row therein? How do I get around this?

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

2 个解决方案

#1


3  

Apparently PopulateEditionList() doesn't attach the editions to the context. Add this line in the foreach loop:

显然,PopulateEditionList()不会将版本附加到上下文。在foreach循环中添加以下行:

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

Possibly you can simplify the whole procedure. I'm not sure why you load the editions into memory. You could just create a "stub entity" based on the key which is enough to create the relationship. Also attaching classifieds to the context seems redundant because you want to add it as a new entity to the database. Trying to load related editions from the database for a parent entity that doesn't exist yet in the DB seems redundant as well. The result can only be an empty collection.

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

So, the following simpler version might work as well:

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

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);
    }
    //...
}

#2


0  

The problem was that EditionModel was not part of the context. Thank you, Slauma for pointing me in the right direction. The corrected Create Action is:

问题是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);
}
...

The rest of the code is as above.

其余代码如上所述。

#1


3  

Apparently PopulateEditionList() doesn't attach the editions to the context. Add this line in the foreach loop:

显然,PopulateEditionList()不会将版本附加到上下文。在foreach循环中添加以下行:

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

Possibly you can simplify the whole procedure. I'm not sure why you load the editions into memory. You could just create a "stub entity" based on the key which is enough to create the relationship. Also attaching classifieds to the context seems redundant because you want to add it as a new entity to the database. Trying to load related editions from the database for a parent entity that doesn't exist yet in the DB seems redundant as well. The result can only be an empty collection.

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

So, the following simpler version might work as well:

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

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);
    }
    //...
}

#2


0  

The problem was that EditionModel was not part of the context. Thank you, Slauma for pointing me in the right direction. The corrected Create Action is:

问题是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);
}
...

The rest of the code is as above.

其余代码如上所述。