【问题标题】:How to use a dynamic expression for a value in an Entity Framework select clause如何在实体框架选择子句中对值使用动态表达式
【发布时间】:2017-11-30 19:04:56
【问题描述】:

我不确定我是否正确地提出了这个问题,或者以一种可以理解的方式,但它是这样的:

我正在尝试找出一种动态方法来在数据库上下文的选择中设置值。我在整个代码中的一百多个地方都使用了我称之为 CodeTableValuePOCO 的东西,而且我不想在每次需要时都指定整个表达式(尤其是查找 CodeName 值的语法)。因此,我尝试使用这样的表达式来动态生成它。

internal static Expression<Func<CodeTableValue, CodeTableValuePOCO>> GetCodeTableValueSelectorExpression(int languageId) {
        return x => new CodeTableValuePOCO
        {
            Code = x.Code,
            // Check if there are any translations for the code name
            CodeName = x.Translations != null
                        // If there are, check if there is a translation for user's language
                        ? x.Translations.LanguageTranslationTexts.Count(t => t.Language_ID == languageId) > 0
                            // If there is a translation, take the first for the given language
                            ? x.Translations.LanguageTranslationTexts.FirstOrDefault(t => t.Language_ID == languageId).Text
                            // Else, default to codeName
                            : x.CodeName
                        // Else, default to codeName
                        : x.CodeName,
            CodeTableId = x.CodeTable.CodeTableID,
            Id = x.CodeTableValueID,
            Key = x.CodeTable.Key,
            ParentId = x.ParentID
        };
    }

但是,我不知道如何在我的代码中使用上述表达式。我认为如果我只是在寻找 CodeTableValuePOCO 就可以了 ,但 CodeTableValuePOCO 嵌入在较大的选择中,如下例所示。显然,它不起作用,因为程序需要一个 CodeTableValuePOCO,但得到一个表达式。

using (MyDbContext db = new MyDbContext()) {

    return db.Notifications
        .Where(x => x.id == 1)        
        .Select(x => new NotificationPOCO
        {
            Id = x.Id,
            Message = x.Message,
            //This part is, obviously, not working
            Type = code.GetCodeTableValueSelectorExpression(2)
         })
         .ToList();
        }
}

【问题讨论】:

  • 真的是code.GetCodeTableValueSelectorExpression(2) - 即它不依赖于您选择的每一行吗?如果是这样,它可以很容易地作为预先计算的值取出(是的,它可能意味着两次往返 DB 调用,但在您看到这导致实际的性能问题之前,我不会太担心它)。另一方面,如果GetCodeTableValueSelectorExpression( ) 是一个必须为每条被选中的记录执行的内部查询,那么您可以通过几种不同复杂度的方法来处理它,包括手动构建表达式树。
  • 顺便说一句,假设你的意思是后者,你有没有试过只做x.CodeTables.Select( GetCodeTableValueSelectorExpression(2) ) 看看有没有用?
  • 谢谢,但是不,它是一个单独的 codeTableValue,不是一个集合,但是,可以有数千个父项,所以我不能让它成为两个单独的查询。
  • 我还是有点困惑 - 正如所写,GetCodeTableValueSelectorExpression() 返回一个接受 CodeTableValue 的函数的表达式,但在您的示例中,您实际上并没有尝试调用返回 - 假设您是,CodeTableValue 参数来自哪里?如果父查询中的每一行没有不同的东西,那么它肯定可以被取出。

标签: c# entity-framework lambda linq-to-sql expression-trees


【解决方案1】:

没有自然的 C# 编译时支持在其他表达式中使用表达式。

您需要一些表达式组合库 - 例如,LINQKit。它解释了问题并使用自定义 InvokeAsExpandable 扩展方法解决了它。您的解决方案是这样的(安装软件包后):

using LinqKit;

using (MyDbContext db = new MyDbContext()) {
    var codeTableValueSelector = GetCodeTableValueSelectorExpression(2); 
    return db.Notifications.AsExpandable()
        .Where(x => x.id = 1)        
        .Select(x => new NotificationPOCO
        {
            Id = x.Id,
            Message = x.Message,
            Type = codeTableValueSelector.Invoke(x) // or x.CodeTable? not sure from the sample code
        })
        .ToList();
}

【讨论】:

  • 这看起来像我想要的。我安装了 Microsoft 的 DynamicLibrary (System.Linq.Dynamic)。你知道我是否可以在其中做类似的事情吗?
  • 也许你可以。但我不记得语法(如果有的话)——你知道这很不寻常。您必须使用非常不寻常的语法生成选择字符串才能对其进行解析并最终处理。等等..现在我记得你不能用动态 LINQ 做new NotificationPOCO
  • 我试过 LinqKit,但得到了这个:LINQ to Entities does not identify the method 'BLL.POCO.CodeTableValuePOCO Invoke[CodeTableValue,CodeTableValuePOCO](System.Linq.Expressions.Expression1[System.Func2[BLL .POCO.CodeTableValuePOCO]], DAL.Models.CodeTableValue)' 方法,并且该方法不能翻译成存储表达式。
  • 您在我的示例中添加了AsExpandable 吗?实际需要对查询表达式树进行后期处理,替换Invoke方法。
  • 是的!那行得通!太感谢了。我一直在为此撕扯头发。顺便说一句,AsExpandable 是做什么的?
猜你喜欢
  • 1970-01-01
  • 2011-12-09
  • 2011-05-11
  • 1970-01-01
  • 2010-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多