实体框架实体中的无效属性优先于分配 ID

问题描述 投票:0回答:1

我目前遇到的情况是,我清除了另一个实体的实体引用,然后再将其分配回来。当我执行 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; }
}
c# .net sql-server entity-framework entity-framework-6
1个回答
0
投票

在使用导航属性时,我建议使用 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 执行这些更新。

© www.soinside.com 2019 - 2024. All rights reserved.