繁体   English   中英

EF6:在DbSet.Local中包含导航属性

[英]EF6: Include Navigation Properties in DbSet.Local

我正在从外部源加载数据作为xml,它被反序列化然后我循环对象以将它们汇集到我的域实体中。

为了创建数据之间的关系并减少数据库调用,我编写了一个扩展方法,尝试从DbSet.Local中检索项目,如果它没有找到项目,那么它使用DbSet.SingleOrDefault()来查询数据库,如下所示。

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);
    }

try catch块可以解决我想要解决的问题。

由于某种原因,未填充查询本地存储时的导航属性。 所以,如果我使用类似的东西

(x=>x.Participant.Event.ExternalId==newItem.Id)

作为我的lambda,Participant nav属性为null。

我觉得应该有一些方法让这段代码不能始终如一地生成空引用错误。

我已经尝试在循环开始使用之前从数据库中显式加载Participant和Event数据

context.Participant.Load()

但这没什么区别。

有人能告诉我为什么导航属性为null以及如何以最有效的方式填充它们?

而且,如果有人想知道我为什么不使用Find(),那是因为外部数据被键入了许多属性以及外部id字段,而不是我系统中的主键。

更新:

我不打算花时间来包含我的真实代码,因为有太多的东西要削减到一个可用的例子,所以我将尝试使用Customer / Order / OrderItem典型示例。

真正的问题是,当你有一个嵌套的实体,并尝试使用类似的东西检查存在:

var orderLine = context.OrderLineItems.Local.SingleOrDefault(x=>x.Order.Number == 1234)

即使Orders和Customers在使用之前明确加载到上下文中,它也会为Order抛出一个null引用错误

context.Orders.Load()

但是,如果你这样做:

var orderLine = context.OrderLineItems.SingleOrDefault(x=>x.Order.Number == 1234)

它会工作。

我想了解为什么它在调用Local时不起作用。 为什么我们必须访问数据库以获取已经加载到上下文中的相关导航属性? 还是我错过了什么?

好吧,我不确定为什么DbSet.Local.xx的行为与DbSet.xx不同,但我最终用作解决方案只是在我的lambda中检查null:

SingleOrDefaultLocalFirst(x=>
...
x.Participant!=null &&
x.Participant.Event.ExternalId==newItem.Id &&
...);

这似乎阻止了我的扩展方法在首先检查Local项时抛出错误,因此优雅地移动到调用数据存储。

这里的问题是你“反序列化”的对象不是Proxied。

当您从DbSet<T>获取项目时,实体框架不会为您提供类型为T对象。 相反,它会创建一个新类TProxy ,它overrides关联属性。 这样,当你get属性时,Entity Framework就会知道,并且可以拦截调用。

通过在Entity Framework之外反序列化对象,它没有机会将“钩子”添加到getter,它需要延迟加载。 因此,当您调用get对象的属性时,EF不会延迟加载。

解决方案是使用Entity Framework实例化所有T对象,然后反序列化为这些对象,然后附加它们。

DbSet<T> set = ...;
T item = set.Create();
T deserialized = Deserialize(..);
AutoMapper.Map(deserialized, item);
set.Attach(item);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM