简体   繁体   English

使用LinqKit和EFCore进行快速加载

[英]Eager Loading with LinqKit and EFCore

B"H B“高

C#sharps inclusion of linq right into the language is one of its most powerful features. C#将linq正确地包含在语言中是其最强大的功能之一。 It is also what makes Entity Framework such an enticing option for working with a database. 这也是使Entity Framework成为使用数据库的诱人选择的原因。

Unfortunately due to typing restrictions its often difficult to create centralized expressions to use throughout your project/solution. 不幸的是,由于类型限制,通常很难创建集中的表达式以在整个项目/解决方案中使用。

One answer to that question is LinqKit. 这个问题的一个答案是LinqKit。 This was working great for me in EF 6.x. 在EF 6.x中,这对我来说非常有效。 However when I moved to EF Core, I am facing a showstopper. 但是,当我移至EF Core时,我正面临着一场风头浪尖。

Instead of properly compiled expressions which should then be converted into SQL statement. 而不是正确编译的表达式,然后应将其转换为SQL语句。 What I am getting are function like expressions which don't include their sub expressions in the SQL that they generate. 我得到的是类似表达式的函数,它们在生成的SQL中不包含其子表达式。 Instead they create AsyncLinqOperatorProvider.EnumerableAdapter s which .Net tries to execute (out of an async context) when you access the IEnumerables a few lines later. 相反,它们创建AsyncLinqOperatorProvider.EnumerableAdapter ,当您稍后访问IEnumerables时,.Net尝试执行(在异步上下文之外)。

So the question is: How do I get EF Core to execute the entire expression as one SQL statement and return a complete materialized object? 因此问题是:如何获得EF Core以一个SQL语句的形式执行整个表达式并返回一个完整的物化对象?

Given two classes 给定两个班

    class OrderItemDTO
    {
        public string OrderItemName { get; set; }
    }
    class OrderDTO
    {
        public string OrderName { get; set; }
        public ICollection<OrderItemDTO> OrderItems { get; set; }
    }

I would like to create a global expressions somewhere 我想在某处创建全局表达式

    public static Expression<Func<Order, OrderDTO>> ToDTO = x => new OrderDTO
    {
        OrderName = x.Name,
        OrderItems = x.Items.Select(y => new OrderItemDTO { OrderItemName = y.Name })
    };

Which I would then use somewhere as var orders = await db.Orders.AsExpandable().Select(ToDTO).ToListAsync(); 然后我将在某处使用它作为var orders = await db.Orders.AsExpandable().Select(ToDTO).ToListAsync(); Expecting a fully materialized OrderDTO. 期待完全实现的OrderDTO。

Instead what I get is a DTO with OrderItems as a AsyncLinqOperatorProvider.EnumerableAdapter which causes a race condition when executed 相反,我得到的是带有OrderItems的DTO作为AsyncLinqOperatorProvider.EnumerableAdapter ,这在执行时会导致竞争状况

Call AsQueryable() and then ToList() on your inner collections - EF will then be able to correctly treat this as full projection: 在内部集合上调用AsQueryable() ,然后调用ToList() -EF将能够正确地将其视为完整投影:

public static Expression<Func<Order, OrderDTO>> ToDTO = x => new OrderDTO
{
    OrderName = x.Name,
    OrderItems = x.Items.AsQueryable().Select(y => new OrderItemDTO { OrderItemName = y.Name }).ToList()
};

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

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