gpt4 book ai didi

c# - 违反 PRIMARY KEY 约束 : Cannot insert duplicate key in object

转载 作者:行者123 更新时间:2023-11-30 22:17:33 25 4
gpt4 key购买 nike

当我想要持久化一个复杂的模型时,我得到了这个错误。我想我知道它来自哪里,但我不知道如何解决它。我正在导入一些提要并自动创建对象,包括子项(多对多)。

{"Violation of PRIMARY KEY constraint 'PK_dbo.Parent'. Cannot insert duplicate key in object 'dbo.Parent'. The duplicate key value is (291).\r\nThe statement has been terminated."}

错误不言自明,但如何预防呢? :)

触发它的代码

var parser = new SchoolFeedReader();
var update = parser.GetAll();
var students = Mapper.Map<List<StudentDTO>, List<Student>>(update);
using (var db = new SchoolContext())
{
// I'm updating every night, so clean out the database before import
db.Database.ExecuteSqlCommand("DELETE FROM Student");
db.Database.ExecuteSqlCommand("DELETE FROM Parent");
db.Database.ExecuteSqlCommand("DELETE FROM Subject");
db.Database.ExecuteSqlCommand("DELETE FROM StudentParent");
db.Database.ExecuteSqlCommand("DELETE FROM StudentSubject");

students.ForEach(s => db.Students.Add(s));
db.SaveChanges(); // Triggers the Exception
}

TL;DR

对于一个学校项目,我需要将 3 个 XML 提要导入数据库。

  • Students.xml
  • Parents.xml
  • 主题.xml

在 Students.xml 中,我遇到了一个设计缺陷:固定数量 (3) 的可能父对象。

<student>
<StudentId>100</StudentId>
<Name>John Doe</Name>
<Location>Main Street</Location>
<Parent1>1002</Parent1>
<Parent2>1002</Parent2>
<Parent3/>
</student>
(... more students)

在 Parents.xml 中,事情更简单。

<parent>
<ParentId>1102</ParentId>
<Name>Dad Doe</Name>
<Email>dad@doe.com</Email>
</parent>
(... more parents)

而Subjects.xml也很简单。

<subject>
<StudentId>100</StudentId>
<Name>English</Name>
</subject>
(... more subjects)

模型

所以我创建了 3 个模型,包括 DTO。

public class Student
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long StudentId { get; set; }
public string Name { get; set; }
public string Location { get; set; }

[InverseProperty("Students")]
public virtual ICollection<Parent> Parents { get; set; }
public virtual ICollection<Subject> Subjects { get; set; }
}

public class StudentDTO
{
public long StudentId { get; set; }
public string Name { get; set; }
public string Location { get; set; }

public List<ParentDTO> Parents { get; set; }
public List<SubjectDTO> Subjects { get; set; }
}

public class Parent
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long ParentId { get; set; }
public string Name { get; set; }
public string Email { get; set; }

[InverseProperty("Parents")]
public virtual ICollection<Student> Students { get; set; }
}

public class ParentDTO
{
public long ParentId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public List<StudentDTO> Students { get; set; }

public ParentDTO()
{
Students = new List<StudentDTO>();
}
}

public class Subject
{
public long SubjectId { get; set; }
public string Name { get; set; }
public virtual List<Student> Students { get; set; }
}

public class SubjectDTO
{
public string Name { get; set; }
public List<StudentDTO> Students { get; set; }

public SubjectDTO()
{
Students = new List<StudentDTO>();
}
}

从 XML 到 DTO

Importer 类有这个巨大的 LINQ 查询,可以一次性获得我需要的一切。

var query = from student in _xStudents.Descendants("Student")
select new StudentDTO
{
StudentId = (long)student.Element("StudentId"),
Name = (String)student.Element("Name"),
Subjects = (
from subject in _xSubjects.Descendants("Subject").DefaultIfEmpty()
where (String)student.Element("StudentId") == (String)subject.Element("StudentId")
select new SubjectDTO
{
Name = (String)subject.Element("Name")
}
).ToList(),
Parents = (
from parent in _xParents.Descendants("Parent").DefaultIfEmpty()
group parent by (String)parent.Element("ParentId") into pg
where (String)student.Element("Parent1") == (String)pg.FirstOrDefault().Element("ParentId") ||
(String)student.Element("Parent2") == (String)pg.FirstOrDefault().Element("ParentId") ||
(String)student.Element("Parent3") == (String)pg.FirstOrDefault().Element("ParentId")

select new ParentDTO
{
ParentId = (long)pg.FirstOrDefault().Element("ParentId"),
Name = (String)pg.FirstOrDefault().Element("Name")
}
).ToList()
};

效果很好,一些学生有 2 个 parent ,一些有 1 个,所以我的数据看起来不错。

问题

我的 Global.asax.cs 中有这些 AutoMappers:

Mapper.CreateMap<StudentDTO, Student>()
.ForMember(dto => dto.Parents, opt => opt.MapFrom(x => x.Parents))
.ForMember(dto => dto.Subjects, opt => opt.MapFrom(x => x.Subjects));
Mapper.CreateMap<ParentDTO, Parent>();
Mapper.CreateMap<SubjectDTO, Subject>();

但是当我开始导入时,我的 db.SaveChanges() 出现错误。它提示 Parent 模型上有重复的 ForeignKey。所以我在想:

it's a Many-to-Many relationship, so if John Doe's sister, Jane Doe, tries to insert the same Dad Doe, then it crashes

那么我怎样才能确保整个映射业务对象集对每个实体只有 1 个引用?如何删除重复的爸爸妈妈?我可能也想为 Subject 做这件事。

最佳答案

如果两个或更多student in _xStudents.Descendants("Student")引用相同的父项(通过 id),然后创建两个或更多 ParentDTO s 具有相同的 ID,因此您随后尝试在 Importer 中两次插入相同的主键类。

如果您只是预处理您的 _xParents , 将它们转换为一个新的 ParentDTO 列表,这是 ParentId 唯一的然后你可以在你的 var query 中使用它获取对单个 ParentDTO 的引用引用给定 ParentId PK 的实例。

此代码示例不会对您的代码进行太多更改,因此您可以轻松地将其与原始代码相关联。但是请注意,您可能可以对此进行优化,并且您的 SubjectDTO 也会遇到同样的问题。如果您使用 SubjectDTO.Name,也请列出独一无二(我猜你应该如此)。

var parents = (from parent in _xParents.Descendants("Parent").DefaultIfEmpty()
group parent by (String)parent.Element("ParentId") into pg
select new ParentDTO
{
ParentId = (long)pg.FirstOrDefault().Element("ParentId"),
Name = (String)pg.FirstOrDefault().Element("Name")
// you might want to not use ToList here and let parents be an IEnumerable instead
}).ToList();

var query = from student in _xStudents.Descendants("Student")
select new StudentDTO
{
StudentId = (long)student.Element("StudentId"),
Name = (String)student.Element("Name"),
Subjects = (
from subject in _xSubjects.Descendants("Subject").DefaultIfEmpty()
where (String)student.Element("StudentId") == (String)subject.Element("StudentId")
select new SubjectDTO
{
Name = (String)subject.Element("Name")
}
).ToList(),
Parents = (
from parent in parents
// Calling ToString each time is not fantastic
where (String)student.Element("Parent1") == parent.ParentId.ToString() ||
(String)student.Element("Parent2") == parent.ParentId.ToString() ||
(String)student.Element("Parent3") == parent.ParentId.ToString()

select parent
).ToList()
};

关于c# - 违反 PRIMARY KEY 约束 : Cannot insert duplicate key in object,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16672309/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com