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;}
}
有什么想法吗?
感谢卡斯滕我想到了可能发生这种情况的原因:
此行为差异是长期存在的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!
}