尝试更新Db时出现相同的主键错误

本文关键字:错误 更新 Db | 更新日期: 2023-09-27 18:27:52

我的应用程序是一个电影收藏管理器。我创建了一个EF模型第一个数据库。我有一个具有Pictures属性的Person实体,它是Picture实体的集合。

给定一个电影标题,我从网上获取所有信息,并获得演员(= Person entities)的列表。对于它们中的每一个,我都创建了一个新的List<Picture>和一个新Picture对象,其中包含从网络上抓取的图片。

对于每个PersonPictures属性中的唯一图片具有相同的Id属性(因为它们都是独立的List<Picture>)。所以当我尝试更新数据库时,会抛出一个DbUpdateException,上面写着

多个添加的实体可能具有相同的主密钥

很容易理解,但我一直认为EF会自己处理所有这些事情(也就是说,将每个Person.Pictures集合中的每个Picture放在Picture表中会给它一个不同的Id)。

显然情况并非如此。为了处理这个问题,我必须在Picture表中直接创建一个Picture,根据我的模型,这对我来说毫无意义:一张照片被附加到一个人身上,所以我在创建Person对象时创建它。如果不是,那么使用模型优先的方式有什么好处?

我是不是错过了处理这个问题的方法?

附言:请看我简化模型的图片,说明所有的东西是如何相互连接的。

更清楚地说,流程是如何运行的(我把负责解析html代码的代码放在一边,以便从网页中获取信息;multipleItems包含一组经过解析的htmldiv):

foreach (var act in multipleItems)
{
     Person myact = new Person();
     List<Picture> mylistpics = new List<Picture>();
     Picture mypic = new Picture();
     mypic.Data = /*[...code for creating image from web data...]*/
     mylistpics.Add(mypic);
     myact.Pictures = mylistpics;
     //[...]code for grabbing name of actor in webpage[...]
     myact.FirstName = names[0];
     myact.Name = names[1];
     mypersons.Add(myact);
}
mymovie.Actors = mypersons;

所以你可以看到,这是重要的一点,我把图片添加到PersonPictures属性中。因此,每个Person都有自己独立的图片集合:对于每个Person的集合,添加的图片Id为0是正常的。

循环结束后,我会将mypersons列表影响到窗口(电影对象)的当前DataContext的Actors属性。

然后,在Dbcontext.SaveChanges();调用(将整个Movie对象保存到数据库)上抛出异常。

转到此处查看"图片人关联"的属性窗格。

尝试更新Db时出现相同的主键错误

您的数据库似乎没有图片Id作为标识字段,因此如果不设置Id,默认值(可能为0)将导致所有相同的主键。将IDENTITY添加到数据库表并更新EF模型后,您应该注意到该列将Id字段的StoreGeneratedPattern属性设置为identity,以便将其配置为使用标识插入中生成的主键。

您让EF很难在代码中遵循实体关系。试试这个,这对人类和EF来说都更可读:

Person myact = new Person
        {
          FirstName = names[0],
          Name = name[1],
          Pictures = new List<Picture>
                     {
                       new Picture { Data = previouslyComputedData }
                     }
        }

此外(或可选),您还可以显式地为Picture对象指定不同的Id(为负数以确保没有任何干扰)。EF将在SaveChanges:上覆盖它们

int picId = -1;
...
          new Picture { Id = picId--, Data = previouslyComputedData }

更新:也许EF不喜欢把这些演员都加在一起。尝试在每次创建Person后保存更改:

Person myact = new Person { ... }
mymovie.Actors.Add(myact);
// SaveChanges();