【问题标题】:Using Function in Select Clause of Entity Framework Query在实体框架查询的 Select 子句中使用函数
【发布时间】:2011-06-21 18:28:15
【问题描述】:

我想针对实体框架实现以下逻辑。

var items = from item in myContext
            select new {
                Value1 = TweakValue(item.Value1),
                Value2 = TweakValue(item.Value2)
            };

protected int TweakValue(int value)
{
    // Custom processing here
    return value;
}

这不起作用,因为在 select 子句中调用了 TweakValue()。我了解查询转换为 SQL,问题是 TweakValue() 无法转换为 SQL。我的问题是实现这一点最经济的方法是什么。我需要第二个循环来转换这些值吗?

我仍在努力适应 LINQ 表达式。

【问题讨论】:

  • TweakValue 有什么作用?或许可以让数据库来做这项工作

标签: c# .net linq entity-framework


【解决方案1】:

最简单的方法可能是将执行“移动”到客户端以执行转换。在这种情况下,您只需使用:

var items = myContext.Select(item => new { item.Value1, item.Value2 })
                     .AsEnumerable()
                     .Select(item => new {
                                 Value1 = TweakValue(item.Value1),
                                 Value2 = TweakValue(item.Value2)
                             });

请注意,您没有必须重复使用 Value1Value2 的名称 - 这样做是最简单的。

如果你真的想使用查询表达式:

var query = from item in myContext
            select new { item.Value1, item.Value2 };

var items = from item in query.AsEnumerable()
            select new {
                Value1 = TweakValue(item.Value1),
                Value2 = TweakValue(item.Value2)
            };

如果您想先执行过滤,您可以通过在调用AsEnumerable() 之前放置过滤、排序等,让 出现在数据库中。例如:

var query = from item in myContext
            where item.Foo == bar
            orderby item.Something
            select new { item.Value1, item.Value2 };

var items = from item in query.AsEnumerable()
            select new {
                Value1 = TweakValue(item.Value1),
                Value2 = TweakValue(item.Value2)
            };

【讨论】:

  • 这与他的查询有很大不同。他从数据库中提取了两个字段。你的拉了整行。
  • 谢谢乔恩。事实上,我的实际查询中有一个where 子句。所以你的最后一个例子可能就是我要使用的。
  • @Craig:正确。但是,在 select 子句中创建一个包含我需要的列的匿名类型将是一件简单的事情。
  • 值得注意的是,@CraigStuntz 的评论是无关紧要的,现在 Jon 已经为 2011 年后签入的任何人编辑了他的答案。
【解决方案2】:

您不需要循环,只需另一个投影:

var items =  myContext.Select(i => new {
                 Value1 = item.Value1,
                 Value2 = item.Value2
             })
             .AsEnumerable()
             .Select(i => new {
                 Value1 = TweakValue(item.Value1),
                 Value2 = TweakValue(item.Value2)
              });

编辑:根据TweakValue 的实际操作,您可以将整个内容推送到服务器。重复您当前的示例:

public Expression<Func<Item, ItemProjection>> TweakValue()
{
    return item => new ItemProjection 
                   {
                       Value1 = item.Value1,
                       Value2 = item.Value2 + 0 // or something else L2E can understand...
                   }; 
}

现在像这样使用它:

var exp = TweakValue();
var items =  myContext.Select(exp);

请注意,我将exp 存储在一个变量中,这样L2E 就不会尝试在查询中直接调用TweakValue,这会失败。

当然,这只有在 TweakValue 做了 L2E 可以做的事情时才有效。

【讨论】:

  • 请注意,您可以使用投影初始化器使第一个 Select 调用稍微简单一些; C# 编译器将从用于初始化它们的属性中默认匿名类型中的属性名称。
  • @Jon,同意,前提是它们只是简单的属性引用。由于我的 50% 的 EF 查询可能更复杂,所以我不会做那么多,因为它会在以后产生维护问题——第一次给定的查询需要的不仅仅是对单个对象的属性的引用,我必须重写整个东西以使用显式命名的属性。
  • @Craig:为什么?毕竟,你只需要重写需要做不同事情的位。
  • @Jon:因为我的大多数带有预测的 L2E 查询最终都不是微不足道的。 IOW,“需要做不同事情的位”是大部分查询。
  • @Craig:嗯,这不是你说的……你给人的印象是你在 any 之后就重写了 whole 查询它的一部分需要改变,你当然不需要这样做。为什么不在可以使用的地方使用它,而在不需要的地方不用呢?您声称它会造成维护问题,但我不明白为什么......这不像是存在兼容性问题。
猜你喜欢
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多