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; }
}
有什么想法吗?
谢谢卡斯滕
我想到了为什么会发生这种情况:
- 上下文中从延迟加载更改为急切加载(参见 here),因此在
首先 SaveChanges,访问用于从数据库加载它的 EditorSettings 属性。
- 数据库中已存在具有该特定 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。
我有一个新问题,我不知道它是怎么来的。
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; }
}
有什么想法吗? 谢谢卡斯滕
我想到了为什么会发生这种情况:
- 上下文中从延迟加载更改为急切加载(参见 here),因此在 首先 SaveChanges,访问用于从数据库加载它的 EditorSettings 属性。
- 数据库中已存在具有该特定 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。