在n层应用程序中,我一直采用从存储库类返回分离的实体的方法。然后,我先进行手动附加,然后再进行更改。一切顺利,直到出现这种新情况为止……
我使用以下代码段从实体内部访问上下文:
public abstract class EntityBase
{
protected TheLeegzDbContext GetDbContext()
{
ObjectContext object_context = this.ObjectContext();
if (object_context == null || object_context.TransactionHandler == null)
{
return null;
}
return (TheLeegzDbContext)object_context.TransactionHandler.DbContext;
}
private ObjectContext ObjectContext()
{
var field = this.GetType().GetField("_entityWrapper");
if (field == null)
{
return null;
}
var wrapper = field.GetValue(this);
var property = wrapper.GetType().GetProperty("Context");
var context = (ObjectContext)property.GetValue(wrapper, null);
return context;
}
}
这似乎适用于尚未分离的对象。但是,当我通过.AsNoTracking()。FirstOrDefault()分离它,然后稍后再附加时,该行:
var field = this.GetType().GetField("_entityWrapper");
返回null。
总而言之,如果我不分离对象,则上一行会检索上下文,但是如果我分离然后重新附加对象,则上述行会失败(请注意:我将其附加到与检索对象相同的上下文中- -不确定这是否重要?!)。
之所以这样做,是因为在添加子实体(未急切加载)时,根聚合需要加载子实体以与“ ordinals”一起玩,以防新子被“插入”。所以,我想:
1)检索根对象并分离,然后...以后... 2)将根对象附加到上下文 3)调用“ AddChild”到根对象,(子对象包括属性“ Ordinal”) 4)让根对象使用GetDbContext()。Entry(this).Collection(e => e.Children).Load();加载现有的子对象。 5)如果新项的序数需要在现有子级的中间插入,则让根对象操纵现有子级对象以“移动”现有子级的序数。
例如
void AddChild(Child child)
if (this.Children == null)
GetDbContext().Entry(this).Collection(e => e.Children).Load();
// Update ordinals of some children if new child ordinal requires inserting.
问题是。根的附加似乎没有提供字段“ _entityWrapper”,就像从数据库中检索并仍被跟踪一样。
我能做到这一点吗,或者如果我想插入一个新的孩子,是否必须急于加载现有的孩子?
答案 0 :(得分:1)
您所确定的行为是设计使您拥有context.Configuration.ProxyCreationEnabled = false
的 IF 。
在这种情况下,当您使用.AsNoTracking()
加载数据时,返回的对象的类型应该是您的POCO数据类,否则EF将返回该类的代理版本,其中包括名为{{1}的其他字段}。
即使禁用了跟踪,您的逻辑约定也取决于
_entityWrapper
的可用性,因此您在加载数据之前应在上下文中设置_entityWrapper
。
正如您的ProxyCreationEnabled = true
类所期望的那样,您应该在上下文中编辑构造函数以将配置设置为强制代理,或者使用其他工厂方法在使用之前预初始化上下文。将其放在
EntityBase
中是不合适的,因为必须在创建实体之前在上下文中对其进行配置。
EntityBase.GetDbContext()
当您将实体附加到上下文时,对象的类型实际上并没有神奇地变回代理类型,因此这解释了为什么在您的对象中没有称为{的 field {1}}在附加之前,它不可能在附加之后 。
要更改类型,将需要创建一个新类型的全新实例,并克隆所有属性值,您需要一个赋值运算符来执行此操作。尝试从创建的条目访问实体的事件不会提供作为代理类型的解析(尽管我认为应该是我第一次尝试使用它),因此以下重新分配不起作用,结果仍然是原始项目实例:
// Force _entityWrapper proxy generation for all queries
context.Configuration.ProxyCreationEnabled = true;
注意::当序数处理很重要,并且您尝试在C#中进行管理(在将子记录更新或插入到数据库中之前),然后在
_entityWrapper
,您永远不能百分百确定自己要添加到集合中的物品,尝试将所有物品加载到列表中是正确的,但是item = dbContext.Entry(item).Entity;
仅会引入列表中还没有的记录,您应该考虑刷新列表中 current 项的所有 ordinal 字段(如果有),在如果自从上次为当前上下文加载列表以来,任何并行操作都可能影响列表。
最后,即使启用了代理,如果您的N-Tier结构涉及将对象序列化并随后反序列化的层,则即使在序列化之前已跟踪对象,通常也不应在反序列化结果中完全获得代理。