“İfade gövdesine sahip bir lambda ifadesi bir ifade ağacına dönüştürülemez”


181

Aşağıdaki kodu derlemeye çalışırken EntityFramework kullanırken, " A lambda expression with a statement body cannot be converted to an expression tree" hatasını alıyorum :

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

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

Hatanın ne anlama geldiğini ve en önemlisi nasıl düzeltileceğini bilmiyorum. Herhangi bir yardım?


6
bu listeye dönüştürmeyi deneyin. Liste (). (...
nelson eldoro

Yanıtlar:


114

objectsbir Linq To-SQL veritabanı bağlamda? Bu durumda, yalnızca => operatörünün sağındaki basit ifadeleri kullanabilirsiniz. Bunun nedeni, bu ifadelerin yürütülmemesi, ancak veritabanına karşı yürütmek için SQL'e dönüştürülmesidir. Bunu dene

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

102

IEnumerable koleksiyonları için lamba ifadesinde ifade gövdesini kullanabilirsiniz . bunu dene:

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

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

Uyarı:
Bu yöntemi kullanırken dikkatlice düşünün, çünkü bu şekilde, kodunuzun geri kalanında istenmeyen yan etkilere neden olabilecek tüm sorgu sonucunu belleğe alırsınız.


4
+1 Bunu beğendim! AsEnumerable()Maskes ekleyerek sorunum gider!
Joel

5
Bu gerçek çözümdür, kabul edilen cevabın bazı durumlarda uygulanması zordur
Ferran Salguero

15
Hayır, bu gerçek cevap değil. Sorgunuzun istemci tarafında yürütülmesini sağlar. Ayrıntılar için bu soruya bakın: stackoverflow.com/questions/33375998/…
Luke Vo

1
@DatVM ne yapacağınıza bağlıdır. bu her zaman doğru seçim olamaz ve elbette her zaman yanlış seçim olamaz.
Amir Oveisi

3
Size katılıyorum, ancak OP EntityFramework kullandığını belirtti. Çoğu durumda, EF ile çalışırken, veritabanı tarafının mümkün olduğunca fazla iş yapmasını istiyorsunuz. Cevabınızdaki vakayı not etmeniz güzel olurdu.
Luke Vo

39

Bu, lambda ifadesinin bir ifade ağacına dönüştürülmesi gereken yerlerde (örneğin linq2sql kullanıldığında olduğu gibi) "ifade gövdesi" (yani kıvırcık ayraç kullanan lambda ifadeleri) içeren lambda ifadelerini kullanamayacağınız anlamına gelir. .


37
Siz ... hatayı biraz yeniden ifade ettiniz. Tim Rogers'ın cevabı çok daha iyiydi
vbullinger

2
@vbullinger bir dereceye kadar haklısınız, ancak daha genel anlamda (linq--sql bağlamının dışında) bu daha doğrudan bir cevap. Bir AutoMapper hatasıyla bana yardımcı oldu
mlhDev

1
vbullinger: Yine de bana yardımcı oldu.
Paul

7

Ne yaptığınız hakkında daha fazla bilgi sahibi olmadan (Linq2Objects, Linq2Entities, Linq2Sql?), Bu onu çalıştırmalıdır:

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

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

11
Bu, sorgulanabilir olanı değerlendirmeye zorlar.
smartcaveman

Ancak, bu durumda sorun değil, çünkü hemen sonra ToArray () 'ı çağırıyor.
smartcaveman

2
illa ki değil - "o" nun ne kadar büyük olduğunu kim bilebilir? İstediğimiz her şey 2 olduğunda 50 mülk sahibi olabilir.
kdawg

1
Bu tekniği kullanırken, aramadan önce anonim bir tipte kullanacağım alanları seçmek istiyorum.AsEnumerable()
Blake Mitchell

4

Bu aşırı yükleme seçeneğini kullanın:

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

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

Bu benim için çalışıyor ama Entity Framework ile birlikte kullanıldığında bu çözüm, dbcontext'in AsEnumerable () gibi ilk olarak tüm satırları belleğe yüklemesini engeller mi?
parlamento

2
@parliament: Tüm satırların belleğe yüklenmesini önlemek için kullanmalısınız Expression<Func<Obj,Obj>>.
Mohsen

4

LINQ to SQL dönüş nesnesi IQueryablearabirimi uyguluyorlardı . Bu nedenle Selectyöntem yüklem parametresi için yalnızca gövdesiz tek bir lambda ifadesi sağlamalısınız.

Bunun nedeni, SQL kodu için LINQ, SQL sunucusu veya diğerleri gibi uzak tarafta değil programın içinde yürütülmemesidir. Bu tembel yükleme yürütme türü, beklenen temsilcisinin aşağıdaki gibi İfade türü sınıfına sarıldığı IQueryable uygulanarak elde edildi.

Expression<Func<TParam,TResult>>

İfade ağacı, vücut ile lambda ifadesini desteklemez ve tek satırlı lambda ifadesini var id = cols.Select( col => col.id );

Yani denerseniz aşağıdaki kod çalışmaz.

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

Aşağıdaki beklendiği gibi çalışacaktır.

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

2

Bu, bir içeren bir Lambda ifadesinin TDelegatebir 'e ([parameters]) => { some code };dönüştürülemeyeceği anlamına gelir Expression<TDelegate>. Kural bu.

Sorgunuzu basitleştirin. Sağladığınız şu şekilde yeniden yazılabilir ve derlenir:

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

1

Arrbir taban türü Obj? Obj sınıfı var mı? Kodunuz yalnızca Arr temel bir Obj türü olduğunda çalışır. Bunun yerine bunu deneyebilirsiniz:

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

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

1

Özel durumunuz için, vücut bir değişken oluşturmak içindir ve IEnumerabletüm işlemleri istemci tarafında işlenmeye zorlayacak şekilde geçiş yapmak için aşağıdaki çözümü öneriyorum.

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();

Düzenleme: C # Kodlama Sözleşmesi için Yeniden Adlandırma

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.