首页 > 解决方案 > 插入包含集合导航属性的实体

问题描述

我有两节课:

public class Student
{
    public int StudentID { get; set; }
    public List<Course> Courses { get; set; }
}

public class Course
{
    public int CourseID { get; set; }    
    public string Name { get; set; }
}

还有一个上下文:

public class DBContext: DbContext
{
    public DbSet<Student> Students { get; set; }
    public DbSet<Course> Courses { get; set; }
    public DBContext(DbContextOptions<DBContext> options) : base(options) { }
}

课程和学生可以彼此独立存在。换句话说,我可以先创建一个课程,然后创建一个学生并将它们与课程相关联。

例如:

var options = new DbContextOptionsBuilder<DBContext>().UseSqlite("Data Source=.\\test.db;");

Course course = null;

using(var context = new DBContext(options.Options))
{
    context.Database.EnsureCreated();
}

using (var context = new DBContext(options.Options))
{
    course = context.Courses.Add(new Course { Name = "Algebra" }).Entity;
    context.SaveChanges();
}

using (var context = new DBContext(options.Options))
{
    var student = context.Students.Add(new Student { Courses = new List<Course> { course } });
    context.SaveChanges();
}

但是,在最后一个上下文范围内,我得到一个唯一约束错误。我知道有些人说我需要在相同的背景下做所有事情。但这在使用例如 WebAPI 微服务架构(StudentService 和 CourseService)时几乎是不可能的。

那么我该如何处理呢?

标签: insertunique-constraintef-core-2.0navigation-properties

解决方案


这里的问题是,在最后一个 using 块context中,不知道该course实例已在先前的操作中保存。

SaveChanges我做了一个小测试,我看到该课程在第二次使用块调用后没有从数据库中分配的 ID 。

通常,执行此操作的最常见方法是从我们需要保存数据的同一上下文中获取实体。所以这会成功。

Course course = new Course { Name = "Algebra" };

using (var context = new DBContext(options.Options))
{
    context.Database.EnsureCreated();
}

using (var context = new DBContext(options.Options))
{
    context.Courses.Add(course);
    context.SaveChanges();
}

using (var context = new DBContext(options.Options))
{
    var courseFromDb = context.Courses.Single(c => c.CourseID == course.CourseID);
    var student = context.Students.Add(new Student { Courses = new List<Course> {courseFromDb}});
    context.SaveChanges();
}

推荐阅读