我目前遇到的情况是,我清除了另一个实体的实体引用,然后再将其分配回来。当我执行 UnitOfCommit.Commit 时,它总是进行 NULL 更新而不是 1111。有没有办法解决这个问题?
顺序
// Clear Reference
divisionTeamPool.DivisionTeam = null;
divisionTeamPool.DivisionTeamId = null;
// No Commit Yet, Assign Same DivisionTeamId
divisionTeamPool.DivisionTeamId = 1111;
// Commit
UnitOfCommit.Commit();
班级
[Table("DivisionTeamPool", Schema = "GrassrootsHoops")]
public class DivisionTeamPool : BaseEntity
{
public virtual int? DivisionTeamId { get; set; }
[ForeignKey("DivisionTeamId")]
public virtual DivisionTeam DivisionTeam { get; set; }
}
在使用导航属性时,我建议使用 FK 或导航属性,不要同时使用两者。原因是正如您所看到的,有两个真相来源,您将遇到的行为将是情境性的,这可能会导致出现意外行为。
如果你有一个 FK 属性和一个导航属性,更新的行为将取决于导航属性的实例是否被跟踪。
举个例子:
using (var context = new AppDbContext())
{
var division = context.Divisions
.Single(x => x.DivisionId == divisionId);
division.DivisionTeamId = newTeamId;
context.SaveChanges();
}
如果该部门现有的团队 ID 为“1”,而新团队 ID 为“2”,那么部门行将在
SaveChanges
上更新 FK,如您所料。但是现在看下一个例子:
using (var context = new AppDbContext())
{
var division = context.Divisions
.Include(x => x.DivisionTeam)
.Single(x => x.DivisionId == divisionId);
division.DivisionTeamId = newTeamId;
context.SaveChanges();
}
这个例子实际上是相同的,除了我们急切加载 DivisionTeam 导航属性。但是现在,保存更改后,Division 的 team ID 仍然是“1”,而不是“2”。原因是在第一个示例中未加载部门的团队引用,因此 EF 将尊重 FK 属性更改。加载引用时,它优先。要可靠地更改两个示例中的 DivisionTeam:
using (var context = new AppDbContext())
{
var newTeam = context.DivisionTeams.Single(x => x.DivisionTeamId == newTeamId);
var division = context.Divisions
.Include(x => x.DivisionTeam)
.Single(x => x.DivisionId == divisionId);
division.DivisionTeam = newTeam;
context.SaveChanges();
}
现在假设您可以更改与 FK 的关系似乎可以,只要您不急切加载导航属性,并且像上面的示例一样 DbContext 是新范围的,这通常没问题。但是,当 DbContext 被注入并可能完成其他操作时,如果 DbContext 恰好正在跟踪任何这些相关实体,您仍然可以获得由 DbContext 填充的相关导航属性,即使没有预先加载。例如:
// Some code higher in the call stack of the request:
var divisionTeam = context.DivisionTeam.Where(x => x.DivisionTeamId == newTeamId);
// Then later when you are doing the update.
var division = context.Divisions
.Single(x => x.DivisionId == divisionId);
division.DivisionTeamId = newTeamId;
即使我们不急于用 Division 加载 Division Team,一些较早的代码可能已经加载了该团队,并且在获取 Divison 时,DbContext 将填充它恰好正在跟踪的与其相关的任何引用。在这种情况下,你会得到相同的行为,团队 ID 不会得到更新。这可能是一个令人沮丧的错误,因为它完全是情境性的,其中一种情况可能会看到关联的相关行,而另一种情况似乎有效。
出于这个原因,我建议在使用导航属性时,为 FK 使用阴影属性并使用导航属性更新关联。如果您需要进行“快速”批量更新,那么请考虑将有界 DbContext 与使用 FK 而不是导航属性的实体一起使用,并使用 FK 执行这些更新。