【问题标题】:Entity Framework code-first IQueryable navigation property实体框架代码优先 IQueryable 导航属性
【发布时间】:2017-01-06 16:36:53
【问题描述】:

我在互联网上看到的大多数示例都将导航属性显示为ICollection 或直接List 实现。它们通常是virtual,以启用延迟加载。

但是,当您访问此类属性时,它会将整个集合加载到内存中,如果您在它之后有一个子查询(即object.MyListProperty.Where(...)),我注意到将为@987654326 中的每个项目发出一个SQL 查询@。

如何避免这种情况?如果可能,我希望 list 属性之后的 where 子句在 SQL 服务器上执行。我可以使用IQueryable 导航属性吗?这种情况有什么最佳实践吗?

【问题讨论】:

  • 我明白你的意思,但不,IQueryable<T> 不是有效的导航属性类型。甚至IEnumerable<T> 也不是。 ICollection<T> 是最小值,当然是从它派生的。

标签: c# entity-framework ef-code-first iqueryable


【解决方案1】:

我对最佳实践的建议是完全禁用延迟加载。而是强制调用者急切地通过包含语句或使用投影来加载导航属性。

有支持包含过滤器的第 3 方产品,如本文所述:How to filter include entities in entity framework,但根据我的经验,这会使检索到的对象的下游处理进一步复杂化。如果实体对象在方法X 之外加载,因为方法X 无法确定导航属性是否已加载正确的过滤器,方法X 通过重新查询精确行开始它知道自己需要。

using (var context = new MyDbContext())
{
    context.Configuration.LazyLoadingEnabled = false;

    // TODO: load your data
    ...
}

这样,只有在明确请求时才会加载记录。

当您想要访问 IQueryable 以便延迟加载数据时,请针对 DbContext 实例而不是对象进行这些查询。

  • 在此示例中,假设 Customer 有数千个事务,因此我们根本不希望它们急切懒惰加载。李>
using (var context = new MyDbContext())
{
    context.Configuration.LazyLoadingEnabled = false;

    var customer = context.Customers.First(x => x.Id == 123);
    ...
    // count the transactions in the last 30 days for this customer
    int customerId = customer.Id;  
    DateTime dateFrom = DateTime.Today.AddDays(-30)

    // different variations on the same query
    int transactionCount1 = context.Customers.Where(x => x.Id == customerId)
                                             .SelectMany(x => x.Transactions.Where(x => x.TransactionDate >= dateFrom))
                                             .Count();
    int transactionCount2 = context.Customers.Where(x => x.Id == customerId)
                                             .SelectMany(x => x.Transactions)
                                             .Where(x => x.TransactionDate >= dateFrom)
                                             .Count();
    int transactionCount3 = context.Transactions.Where(x => x.CustomerId == customerId)
                                                .Where(x => x.TransactionDate >= dateFrom)
                                                .Count();
}

很高兴您已确定要使用IQueryable<T>,我们直接从DbContext 访问它们,而不是从之前检索到的实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多