2010-12-30 9 views
8

SQL davranışına bazı garip LINQ üzerinde tökezledi - Herkes bu konuda bazı ışık tutabilir?LINQ: Yeniden lambda ifadesi

Ben lambda ifade tanımlamak ve benim LINQ açıklamada kullanmak istiyorum. ,

Unsupported overload used for query operator 'Any'. 

Ama:

[...] 
Func<Table1, bool> lambda = x => x.Id > 1000; 
var result = dataContext.Table1s.Where(lambda); 
[...] 

Ama ilişkili bir tabloya

[...] 
Func<Table1, bool> lambda = x => x.Id > 1000; 
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda)); 
[...] 

üzerine yaptığı açıklamada benim Lambda ifade kullanmaya çalıştığınızda istisna almak: Aşağıdaki kod çalışıyor ve bu alamadım:

[...] 
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000)); 
[...] 
: Ben sorgusuna doğrudan benim lambda koymak zaman iyi çalışır

NEDEN ?!

Teşekkürler.

+0

'var lamda = x => x.Id> 1000;' kullanmayı deneyin. Yardım edeceğini bilmiyorum, ama bu olabilir ... – Alxandr

+0

@Alxandr - Bu aslında yasal değil. Lambda ifadeleri 'Func <>' veya 'Expression >' olarak derlenebilir ve örneğinizde derleyici hangisini istediğinizi söyleyemeyebilir ve bir hata atar. –

cevap

18

Tamam, işte anlaşma: dataContext.Table1s tip IQueryable<T> taşımaktadır. IQueryable<T>, Expression<Func<T, bool>> türünde bir yüklemeyi alan Where ve Any yöntemlerini tanımlar. Expression<> sarıcı önemlidir, çünkü LINQ to SQL'in lambda ifadenizi SQL'e çevirmesine ve veritabanı sunucusunda çalıştırmasına izin verir.

Ancak IQueryable<T> da IEnumerable<T> içerir. IEnumerable<T> ayrıca Where ve Any yöntemlerini de tanımlar, ancak IEnumerable sürüm Func<T, bool> türünde bir yüklemi alır. Bu derlenmiş bir işlev olduğu ve bir ifade olmadığı için, SQL'e çevrilemez. Sonuç, bu kod ... gibi

Func<Table1, bool> lambda = x => x.Id > 1000; 
var result = dataContext.Table1s.Where(lambda); 

... belleğe Table1s dışına HER kaydını çekin ve sonra bellekte kayıtları filtreler. Çalışır, ama masanız büyükse gerçekten kötü bir haber.

Func<Table1, bool> lambda = x => x.Id > 1000; 
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda)); 

Bu sürümde iki adet lambda ifadesi vardır. İkincisi, doğrudan Where'a geçirilen, bir Func referansını içeren bir Expression'dur. İkisini karıştıramazsınız ve aldığınız hata mesajı, Any numaralı aramanın Expression numaralı telefona beklediğini, ancak Func numaralı telefonu geçtiğinizi bildirmektir.Bu size kod LINQ to SQL ile SQL dönüştürülmesi istiyorsanız tek seçenek çünkü bu versiyonda

var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000)); 

, iç lambda otomatik olarak Expression dönüştürülür ediliyor. Diğer durumlarda, lambda'nın Expression yerine Func olmasını zorluyorsunuz - bu durumda değilsiniz, bu yüzden çalışır.

Çözüm nedir? Aslında çok basit:

Expression<Func<Table1, bool>> lambda = x => x.Id > 1000; 
+1

+1 gerçekten iyi bir açıklama. –

+0

Teşekkürler. Ne yazık ki derleme yapmaz, derleyici hatası: Bağımsız Değişken 2: 'System.Linq.Expressions.Expression >' dan 'System.Func ' ' –

+1

' dönüştürebilirsiniz. [IEnumerable] (http://msdn.microsoft.com/en-us/library/bb534803.aspx) sürümleri beklediği için IEnumerable'ı değil, IQueryable'ı uygulayan bir nesne üzerinde 'Any' veya 'Any' işlevini çağırır. [IQueryable] (http://msdn.microsoft.com/en-us/library/bb548547.aspx) sürümlerinin bir İfadeyi beklediği Func. Bir İfadeyi kabul etmeyecekse, nesne IQueryable olmayabilir ... –

0

Table1 aynı ad başvurmak mu? İlk örnekte dataContext'un altında olan Table1 nesnelerine karşı sorguladığınız ikinci örnekte, Table2 nesnelerinin bir özelliği olan Table1 nesnelerine karşı sorgulama yapıyorsunuzdur ve son örnekte bir anonim kullanıyorsunuzdur. sorunu gideren işlev.

Ben Table2 nesnenin bir özelliktir Table1 nesnelerin türünü arayabilir ve dataContext doğrudan bağlı bir Table1 nesneye karşılaştırmak istiyorsunuz. Tahminimce onlar farklıdır ve sizin lambda ifadeniz, dataContext'a bağlı nesnenin türünü kullanıyordur.