“具有语句主体的lambda表达式无法转换为表达式树”

时间:2011-03-03 10:17:21

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

在使用 EntityFramework 时,我在尝试编译以下代码时收到错误“A lambda expression with a statement body cannot be converted to an expression tree”:

Obj[] myArray = objects.Select(o =>
{
    var someLocalVar = o.someVar;

    return new Obj() { 
    Var1 = someLocalVar,
    Var2 = o.var2 };
}).ToArray();

我不知道错误意味着什么,最重要的是如何解决它。有什么帮助吗?

10 个答案:

答案 0 :(得分:94)

objects是否为Linq-to-SQL数据库上下文?在这种情况下,您只能在=>右侧使用简单表达式。运营商。原因是,这些表达式不会被执行,而是转换为SQL以对数据库执行。 试试这个

Arr[] myArray = objects.Select(o => new Obj() { 
    Var1 = o.someVar,
    Var2 = o.var2 
}).ToArray();

答案 1 :(得分:85)

您可以在lamba表达式中为 IEnumerable 集合使用语句体。 试试这个:

Obj[] myArray = objects.AsEnumerable().Select(o =>
{
    var someLocalVar = o.someVar;

    return new Obj() 
    { 
        Var1 = someLocalVar,
        Var2 = o.var2 
    };
}).ToArray();

<强>注意:
使用此方法时请仔细考虑,因为这样,您将在内存中获得所有查询结果,这可能会对您的其余代码产生不必要的副作用。

答案 2 :(得分:35)

这意味着你不能在lambda表达式需要转换为表达式树的地方使用带有“语句体”的lambda表达式(即使用花括号的lambda表达式)(例如,当使用linq2sql)。

答案 3 :(得分:5)

在不知道你正在做什么的情况下(Linq2Objects,Linq2Entities,Linq2Sql?),这应该可以使它工作:

Arr[] myArray = objects.AsEnumerable().Select(o => {
    var someLocalVar = o.someVar;

    return new Obj() { 
        Var1 = someLocalVar,
        Var2 = o.var2 
    }; 
}).ToArray();

答案 4 :(得分:3)

使用select:

的重载
Obj[] myArray = objects.Select(new Func<Obj,Obj>( o =>
{
    var someLocalVar = o.someVar;

    return new Obj() 
    { 
       Var1 = someLocalVar,
       Var2 = o.var2 
    };
})).ToArray();

答案 5 :(得分:2)

晚了9年,但是对您的问题采取了另一种方法(没人提到?)

该语句主体可与Func<>配合使用,但不能与Expression<Func<>>配合使用。 IQueryable.Select想要一个Expression<>,因为它们可以为实体框架翻译-Func<>不能。

因此,您可以使用AsEnumerable并开始处理内存中的数据(不建议,如果不是真正必要的话),或者继续使用建议的IQueryable<>。 有一种叫做linq query的东西使事情变得更容易:

IQueryable<Obj> result = from o in objects
                         let someLocalVar = o.someVar
                         select new Obj
                         {
                           Var1 = someLocalVar,
                           Var2 = o.var2
                         };

使用let,您可以定义一个变量并在select(或where,...)中使用它-并继续使用IQueryable,直到您使用确实需要执行并获取对象。

之后,您可以Obj[] myArray = result.ToArray()

答案 6 :(得分:1)

这意味着包含TDelegate的{​​{1}}类型的Lambda表达式无法转换为([parameters]) => { some code };。这是规则。

简化您的查询。您提供的那个可以重写为以下内容并编译:

Expression<TDelegate>

答案 7 :(得分:0)

Arr的基本类型是Obj吗? Obj类是否存在?只有当Arr是Obj的基本类型时,您的代码才有效。你可以试试这个:

Obj[] myArray = objects.Select(o =>
{
    var someLocalVar = o.someVar;

    return new Obj() 
    { 
       Var1 = someLocalVar,
       Var2 = o.var2 
    };
}).ToArray();

答案 8 :(得分:0)

对于您的具体情况,正文用于创建变量,切换到IEnumerable会强制在客户端处理所有操作,我建议采用以下解决方案。

Obj[] myArray = objects
.Select(o => new
{
    SomeLocalVar = o.someVar, // You can even use any LINQ statement here
    Info = o,
}).Select(o => new Obj()
{
    Var1 = o.SomeLocalVar,
    Var2 = o.Info.var2,
    Var3 = o.SomeLocalVar.SubValue1,
    Var4 = o.SomeLocalVar.SubValue2,
}).ToArray();

编辑:重命名为C#编码约定

答案 9 :(得分:0)

LINQ to SQL返回对象正在实现IQueryable接口。因此,对于Select方法谓词参数,您应该只提供没有正文的单个lambda表达式。

这是因为LINQ for SQL代码不是在程序内执行而不是在远程端执行,如SQL Server或其他。这个延迟加载执行类型是通过实现IQueryable实现的,其中期望委托被包装在Expression类中,如下所示。

Expression<Func<TParam,TResult>>

表达式树不支持带有body的lambda表达式,它只支持单行lambda表达式,如var id = cols.Select( col => col.id );

因此,如果您尝试使用以下代码,则无法使用。

Expression<Func<int,int>> function = x => {
    return x * 2;
}

以下内容将按预期运作。

Expression<Func<int,int>> function = x => x * 2;