EF6 虚拟对象不再可用

EF6 virtual objects no longer available

我有一个新问题,我不知道它是怎么来的。

public static int SaveNewProjectGraphic(string svgString, int pageId, ApplicationDbContext db, string user = "System")
    {
        db = new ApplicationDbContext();   //tried with new and with db-context given from controller-action
        LayoutGraphic layoutGraphic = new LayoutGraphic()
        {
            byUser = user,
            EditorSettingId = pageId,
            SvgString = svgString
        };

        db.LayoutGraphics.Add(layoutGraphic);
        db.SaveChanges();
        layoutGraphic.EditorSetting.Project.LastChange = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        layoutGraphic.EditorSetting.Project.byUser = user;
        db.Entry(layoutGraphic.EditorSetting.Project).State = EntityState.Modified;
        string newId = layoutGraphic.Id.ToString();
        string newSvgString = svgString.Replace("newGraphicId", "g" + newId);
        layoutGraphic.SvgString = newSvgString;
        db.Entry(layoutGraphic).State = EntityState.Modified;
        db.SaveChanges();
        return layoutGraphic.Id;
    }

在上面的静态函数中,我创建了一条新记录。
在 db.SaveChanges() 之后,我通常会得到与新记录关联的虚拟记录 (EditorSetting)。
现在我可以使用此关联更改该记录的某些属性(字段)。

我 100% 确定这以前有效但不知何故它被破坏了(不仅在这个模型上),所以我只在 EditorSetting 上得到一个空引用异常(当然还有项目,它与 Editorsetting 相关联).
我不知道我做了什么:-(

这里是 LayouGraphic-model(详细):

public class LayoutGraphic : BaseEntity
{
    [Display(Name = "SVG")]
    public string SvgString { get; set; }

    public int EditorSettingId { get; set; }
    public virtual EditorSetting EditorSetting{ get; set; }
}

以及关联的主模型:

public class EditorSetting
{
    //defaults setzen
    public EditorSetting()
    {
        ViewBox = "0 0 600 500";
        Created = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        LastChange = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    }

    public int Id { get; set; }
    public int ProjectId { get; set; }
    public virtual Project Project { get; set; }

    public string ViewBox { get; set; }
    public string ViewName { get; set; }
    public string Pagenumber { get; set; }

    public string Created { get; set; }
    public string LastChange { get; set; }
    public string byUser { get; set; }

    //1:n Beziehung zu Unterfunktionen
    public virtual ICollection<SubFunction> SubFunctions { get; set; }
}

有什么想法吗? 谢谢卡斯滕

我想到了为什么会发生这种情况:

  1. 上下文中从延迟加载更改为急切加载(参见 here),因此在 首先 SaveChanges,访问用于从数据库加载它的 EditorSettings 属性。
  2. 数据库中已存在具有该特定 ID 的 EditoSetting 对象。如果您在该方法中创建新的上下文,则这无关紧要。然而你提到它用过 在控制器中,所以也许流程中的东西是 改变了。

此行为差异是长期存在的 DbContext 的结果。通过在方法中声明一个新的 DbContext,您将永远不会看到通过在实体上设置 EditorSettingId FK 并保存它来更新 EditorSetting 引用。

当您使用寿命更长的 DbContext 时,您可能看到它更新,前提是 DBContext 知道它。 (引用的 EditorSetting 是 DbContext 中的跟踪实体)

例如:

假设我们有一个父子实体。 Parent包含Children的集合,Child包含一个ParentId FK和一个虚拟的Parent导航属性。父 ID#1 存在于数据库中:

using (var context = new TestDbContext())
{
    var newChild = new Child { Name = "Freddy", BirthDate = new DateTime(1999, 3, 3), ParentId = 1 };
    context.Children.Add(newChild);
    context.SaveChanges();
}

现在 SaveChanges 之后的这一点,如果您查看 newChild 的 Parent 引用,它将是 #null。相反,如果您这样做:

using (var context = new TestDbContext())
{
    var neverUsedParent = context.Parents.Single(x => x.ParentId == 1);

    var newChild = new Child { Name = "Freddy", BirthDate = new DateTime(1999, 3, 3), ParentId = 1 };
    context.Children.Add(newChild);
    context.SaveChanges();
}

在这个例子中,保存更改后你会看到父引用存在,即使我们没有关联它,我们仍然只设置了ID。

当您拥有长期存在的 DbContext 时,必然会在设置 FK 属性时发生行为差异,并且它可能会产生非常奇怪的后果,这些后果会在运行时显示出来。如果其中一个 EditorSettings 先前已由该 DbContext 从数据库加载,则使用该 EditorSettingId 创建新记录将填充关联,而另一个 EditorSettingId 则不会。 (因为 DbContext 不知道它)如果使用了相同的 DbContext 实例,EditorSetting 可能已经加载到此调用之前代码中的任何位置。

即使这样做:

using (var context = new TestDbContext())
{
    var newChild = new Child { Name = "Freddy", BirthDate = new DateTime(1999, 3, 3), ParentId = 1 };
    context.Children.Add(newChild);
    context.SaveChanges();

    // newChild.Parent == #null here....

    var neverUsedParent = context.Parents.Single(x => x.ParentId == 1);

    // newChild.Parent is available here!
}

一般来说,最好避免同时映射导航属性和 FK。我建议实体应该使用其中之一。使用导航属性时,您可以使用 EF Core 中的阴影属性或 EF 6 中的 Map.MapKey() 映射不带属性的 FK。对于我想要 load/manipulate 大量数据并且不需要相关详细信息的情况,我将在这些实体中使用没有导航属性的 FK。