重用LINQ To Entities语句

时间:2015-10-27 21:58:40

标签: c# entity-framework linq linq-to-entities reusability

我有以下Select表达式,将在数据库端执行:

        var model = new ProductListViewModel()
        {
            Products = products
                .Select(q => new ProductViewModel()
                {
                    // Other mapping
                    Name = q.LanguageKey.LanguageValues.FirstOrDefault(p => p.LanguageKeyID == currentLanguageID && p.Active).Value,
                })
                .OrderBy(q => q.Name)
        };

正如您所看到的,Name部分很长,我程序的其他部分也使用相同的逻辑。因此,我想重用它(不是整个Select语句,只是名称映射部分)。

我试着写一个只使用实体的函数:

public static string GetProductName(Product product, int languageID)
{
    return product.LanguageKey.LanguageValues.AsQueryable()
        .FirstOrDefault(q => q.LanguageID == languageID && q.Active).Value;
}

然而,在调用该方法时,我(显然)收到错误

  

LINQ to Entities无法识别方法{X}方法,并且此方法无法转换为商店表达式

我在StackOverflow上搜索了很多文章,但大多数都解决了重用整个Select表达式的问题。是否可以重复使用它?或者我是否必须创建数据库存储过程或函数?

1 个答案:

答案 0 :(得分:2)

一种解决方案是使用LINQKit

首先,您需要修改方法以返回如下表达式:

public Expression<Func<Product, string>> CreateExpression(int languageID)
{
    return product => product.LanguageKey.LanguageValues.AsQueryable()
        .FirstOrDefault(q => q.LanguageID == languageID && q.Active).Value;
}

顺便说一下,我认为你不需要在这里调用.AsQueryable()

然后您可以执行以下操作:

var expression = CreateExpression(currentLanguageID);

var model = new ProductListViewModel()
{
    Products = products.AsExpandable()
        .Select(q => new ProductViewModel()
        {
            // Other mapping
            Name = expression.Invoke(q),
        })
        .OrderBy(q => q.Name)
};

请注意.AsExpandable()变量上的products调用。

此方法来自LINQKit,它在IQueryable(在您的情况下为products)周围创建一个包装器,以便在lambda表达式中使用表达式。

另请注意同样来自LINQKit的Invoke方法。它允许您在其他表达式中使用expression,即q => new ProductViewModel(...