EF Core 一对一关系交换引用问题

Posted

技术标签:

【中文标题】EF Core 一对一关系交换引用问题【英文标题】:EF Core one-to-one relationship swapping references issue 【发布时间】:2020-05-24 14:08:57 【问题描述】:

我有两个实体

public class Student 
    public int Id  get; set; 
    public string Name  get; set; 

    public StudentAddress Address  get; set; 

public class StudentAddress 
    public int StudentAddressId  get; set; 
    public string Address  get; set; 
    public string City  get; set; 
    public string State  get; set; 
    public string Country  get; set; 

    public int StudentId  get; set; 
    public Student Student  get; set; 

基本上是一对一的关系

我有这样的代码

var students = await context.Students.Include(s => s.Address).ToListAsync();

var student1 = students[0];
var student2 = students[1];

var st1Addr = student1.Address;
var st2Addr = student2.Address;

student1.Address = st2Addr;
student2.Address = st1Addr;

await context.SaveChangesAsync();

当 EF 保存更改时,其中一条学生地址记录会从 DB 中删除。

我需要更改对学生地址的引用。如何使用 EF 核心实现这一目标?

【问题讨论】:

能否分享两条记录的底层数据? 【参考方案1】:

因为是1对1的关系,只要你设置好

 student1.Address = st2Addr;

必须删除学生 1 的旧地址,因为它会违反对 SudentAddress.StudentId 的唯一约束。这不仅仅是变更跟踪器的限制。 SaveChanges 将无法运行

UPDATE StudentAddress set StudentId = @StudentId where StudentAddressID = @Id

没有先删除另一行,因为它会违反唯一约束。并且通常对每个 DML 语句强制执行约束,而不是推迟到事务提交之前。您可以在 SQL 中使用单个更新语句来执行此操作,例如

update SudentAddress set StudentID = case when studentId = 1 then 2 else 1 end
where StudentId in (1,2)

如果你明确将删除的地址设置回修改

db.Entry(st1Addr).State = EntityState.Modified;

您会看到 SaveChanges 失败,因为它无法提出使数据库处于所需状态的一系列更改。

System.InvalidOperationException: '无法保存更改,因为 在要保存的数据中检测到循环依赖

所以直接修改 SudentAddress.StudentId 在这里没有帮助。

我认为通过更改跟踪器执行此操作的唯一方法是复制 StudentAddress 实体。然后两个旧的都将被删除并插入新的。

【讨论】:

以上是关于EF Core 一对一关系交换引用问题的主要内容,如果未能解决你的问题,请参考以下文章

具有一对一关系的 EF Core 批量插入

EF Core 中的一对一关系(无法确定一对一关系的子/依赖方)

EF Core中通过Fluent API配置一对一关系

EF Core 中的一对零或一对关系

EF Core 一对一 一对多 多对多 关系定义

EF Core中通过Fluent API配置一对一关系