C# EF6:在DbSet.Local中包含导航属性
我以xml的形式从外部源加载数据,它被反序列化,然后我循环对象,将它们导入到我的域实体中 为了创建数据之间的关系并减少数据库调用,我编写了一个扩展方法,尝试从DbSet.Local中检索项。首先,如果没有找到该项,则使用DbSet.SingleOrDefault()查询数据库,如下所示C# EF6:在DbSet.Local中包含导航属性,c#,entity-framework,dbset,C#,Entity Framework,Dbset,我以xml的形式从外部源加载数据,它被反序列化,然后我循环对象,将它们导入到我的域实体中 为了创建数据之间的关系并减少数据库调用,我编写了一个扩展方法,尝试从DbSet.Local中检索项。首先,如果没有找到该项,则使用DbSet.SingleOrDefault()查询数据库,如下所示 public static TEntity SingleOrDefaultLocalFirst<TEntity>(this IDbSet<TEntity> set, Fun
public static TEntity SingleOrDefaultLocalFirst<TEntity>(this IDbSet<TEntity> set,
Func<TEntity, bool> predicate) where TEntity : class
{
if (set == null)
throw new ArgumentNullException("set");
if (predicate == null)
throw new ArgumentNullException("predicate");
TEntity results = null;
try
{
results = set.Local.SingleOrDefault(predicate);
}
catch (Exception e)
{
Debug.WriteLine(e.Message, "Error");
}
if (results != null)
{
return results;
}
return set.SingleOrDefault(predicate);
}
作为我的lambda,Participant nav属性为null
我觉得应该有某种方法使这段代码不一致地生成空引用错误
在循环开始使用之前,我已尝试从数据库显式加载参与者和事件数据
context.Participant.Load()
但这没什么区别
有人能告诉我为什么导航属性为空以及如何以最有效的方式填充它们吗
如果有人想知道我为什么不使用Find(),那是因为外部数据被键入了许多属性以及一个外部id字段,而该字段不是我系统中的主键
更新:
我不打算花时间包含我的真实代码,因为有太多的东西需要简化为一个可用的示例,所以我将尝试使用Customer/Order/OrderItem典型示例
真正的问题是,当您有一个嵌套实体,并尝试使用以下方法检查是否存在:
var orderLine = context.OrderLineItems.Local.SingleOrDefault(x=>x.Order.Number == 1234)
即使订单和客户在此使用之前已显式加载到上下文中,它也会为订单抛出nullreference错误
context.Orders.Load()
但是,如果您这样做:
var orderLine = context.OrderLineItems.SingleOrDefault(x=>x.Order.Number == 1234)
它会起作用的
我想知道为什么打电话给当地人时它不起作用。当相关的nav属性已经加载到上下文中时,为什么我们必须访问数据库以获取它们?还是我遗漏了什么?这里的问题是您“反序列化”的对象没有代理 当您从
DbSet
中获取项时,实体框架不会为您提供T
类型的对象。相反,它创建一个新类TProxy
,该类覆盖关联属性。这样,当您获取属性时,实体框架就会知道,并且可以拦截调用
通过在实体框架之外反序列化对象,它没有机会向getter添加需要延迟加载的“钩子”。因此,当您在对象的属性上调用get时,EF不会延迟加载
解决方法是使用实体框架实例化所有T
对象,然后反序列化到这些对象中,然后附加它们
DbSet<T> set = ...;
T item = set.Create();
T deserialized = Deserialize(..);
AutoMapper.Map(deserialized, item);
set.Attach(item);
DbSet集=。。。;
T item=set.Create();
T反序列化=反序列化(…);
AutoMapper.Map(反序列化,项);
设置。附加(项目);
嗯,我不确定DbSet.Local.xx的行为为何与DbSet.xx不同,但我最终使用的解决方案只是简单地检查lambda中的null:
SingleOrDefaultLocalFirst(x=>
...
x.Participant!=null &&
x.Participant.Event.ExternalId==newItem.Id &&
...);
这似乎可以防止我的扩展方法在首先检查本地项时抛出错误,因此可以优雅地转到调用数据存储。默认情况下,导航属性不会加载。如果您想动态加载它们,那么使用延迟加载;您应该只需要将属性标记为virtual
。是的,属性是虚拟的,并且使用Load()显式加载数据,因此它们存在于上下文中。我的最新解决方案是首先检查lambda中导航属性的null。这是可行的,但我想知道为什么导航属性在上下文中存在时为空。也许除了我正在做的事情之外,没有其他解决方案。你能发布你的实体类的代码吗?如果你将反序列化对象附加到上下文中,关联应该自动恢复。@Gert反序列化对象不是域实体。为了简化反序列化过程,对象模仿Xml的结构。即使它们通过automapper或其他方式映射到域,它们也不能仅仅被附加,因为它们只会被添加,因为外部数据不包括实体的内部密钥。
SingleOrDefaultLocalFirst(x=>
...
x.Participant!=null &&
x.Participant.Event.ExternalId==newItem.Id &&
...);