Asp.net mvc EF6虚拟对象不再可用

Asp.net mvc EF6虚拟对象不再可用,asp.net-mvc,entity-framework-6,Asp.net Mvc,Entity Framework 6,我有一个新问题,我不知道它是怎么出现的。 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-ac

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

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(当然还有Project,它与EditorSetting关联)上得到一个空引用异常。
我不知道我做了什么:-(

此处为布局图形模型(详图):

以及相关的主模型:

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; }
}
公共类编辑器设置
{
//默认设置
公共编辑设置()
{
ViewBox=“0 600 500”;
Created=DateTime.Now.ToString(“yyyy-MM-dd HH:MM:ss”);
LastChange=DateTime.Now.ToString(“yyyy-MM-dd HH:MM:ss”);
}
公共int Id{get;set;}
公共int ProjectId{get;set;}
公共虚拟项目{get;set;}
公共字符串视图框{get;set;}
公共字符串ViewName{get;set;}
公共字符串页码{get;set;}
已创建公共字符串{get;set;}
公共字符串LastChange{get;set;}
公共字符串由用户{get;set;}
//1:n贝齐洪祖恩
公共虚拟ICollection子函数{get;set;}
}
有什么想法吗?
感谢卡斯滕

我想到了可能发生这种情况的原因:

  • 上下文中有一个从延迟加载到急切加载的变化(请参阅),因此 首先保存更改,访问用于从数据库加载更改的EditorSettings属性
  • 数据库中已存在具有该特定id的EditoSetting对象。如果在该方法中创建新上下文,则这与此无关。无论您提到如何使用它 在控制器中,所以可能流中的某些东西 变了

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

    使用寿命较长的DbContext时,如果DbContext知道它,则可能会看到它被更新。(引用的EditorSetting是DbContext中的跟踪实体)

    例如:

    假设我们有父实体和子实体。父实体包含子实体的集合,子实体包含ParentId FK和虚拟父导航属性。数据库中存在父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
    引用,它将为空。如果您这样做:

    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属性时必然会发生行为上的差异,这可能会产生运行时显示的非常奇怪的结果。如果该DbContext以前从DB加载了其中一个EditorSettings,则使用该EditorSettings ID创建一个新记录将填充关联n、 而另一个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。我建议实体应使用其中一种。使用导航属性时,可以映射FK,而不使用EF Core或
    map.MapKey()中的阴影属性
    在EF 6中。如果我想加载/操作大量数据,并且不需要相关的详细信息,我将使用在这些实体中没有导航属性的FKs。

    我看不到您从何处获取编辑器设置或传递其值。SaveChanges()不会这样做-看。谢谢你的回答,Steve。这听起来很有道理。正如你在参数中所看到的,我也尝试使用现有的dbContext,它在控制器类中使用,但有相同的结果。我的想法是。为了节省时间而不显式加载主记录集,但我认为这是最安全的方法o将来,我更愿意使用控制器的上下文(将其用作参数)并显式加载所需的数据。在创建新子级之前加载现有FK,而不是在创建后加载数据,是否有任何区别?只要导航属性是代理(虚拟)然后,无论实体是在之前还是之后加载,这都会使行为更加不可预测。最安全的方法是只使用FKs或导航属性,而不是同时使用两者。使用两者,即使您非常小心并始终使用nav属性,FK也不会自动更新,直到调用SaveChanges。C将子项从父项1挂起到父项3:在此之前,您将关联ID为3的父项,但子项的ParentId仍报告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();
    
        // newChild.Parent == #null here....
    
        var neverUsedParent = context.Parents.Single(x => x.ParentId == 1);
    
        // newChild.Parent is available here!
    }