2013-09-27 19 views
6

Bir özellik Kimliği seçmek ve bir kimlik listesiyle karşılaştırmak için bir Func alan varlık uzantısı yöntemine bir linq yazmaya çalışıyorum. YöntemLinq'den Entity Framework ile bir ifadede Func nasıl kullanılır?

var ids = new List<int> { 1, 2, 3 }; 
DbContext.EntityAs.WithId(e => e.AId, ids); 
DbContext.EntityBs.WithId(e => e.BId, ids); 

Ben sorun çağrılması

Sınıflar

public class A 
{ 
    public int AId { get; set; } 
} 

public class B 
{ 
    public int BId { get; set; } 
} 

Uzatma Yöntemi

public static IQueryable<T> WithId<T>(this IQueryable<T> entities, 
    Func<T, int> selector, IList<int> ids) 
    { 
     Expression<Func<T, bool>> expression = x => ids.Contains(selector(x)); 
     return entities.Where(expression); // error here (when evaluated) 
    } 

deneyimleme, Entity Framework'de izin verilmeyen işlevi çağırmaya çalıştığıdır.

Sorguyu değerlendirmek için özellik seçici (Func) nasıl kullanabilirim?

+0

Bir EF sorgusunda çağırabileceğiniz kod kapsamı, yine de SQL'de çevrilmesi gereken bir gerçektir. Sizin durumunuzda EF, bir IList'in otomatik olarak nasıl çevrileceğini bilmiyor. –

+0

Bu konuda doğru olduğundan emin değilim. DbContext.EntityAs.Where (e => ids.Contains (e.Id)) EF tarafından doğru bir şekilde çevrilmiştir. Yeniden kullanılabilir bir işlev yapmaya çalışıyorum, böylece hangi özelliği seçeceğimi tanımlayabilirim. – David

+0

EF, nasıl numaralandırılacağını bildiği için, x değeri (1,2,3) içinde numaralandırılabilir (x) 'i seçebilir veya başka bir varlık ilişkisi durumunda x' i (select y) 'yi seçin. Sizin durumunuzda, EF, x'i seçin, x'i seçin (F'yi (y) (F (1), F (2), ...)) 'de seçin. Bunu elle yapmak mümkün olsa da EF sadece durumu desteklemiyor * henüz * –

cevap

15

Func<T, int> yerine Expression<Func<T, int>> geçirmeniz ve tam ifadeyi kendiniz oluşturmanız gerekir. senin O/RM ile çalışırken kodunuzu KURU tutmaya çalıştığınızda

public static IQueryable<T> WithId<T>(this IQueryable<T> entities, 
    Expression<Func<T, int>> propertySelector, ICollection<int> ids) 
{ 
    var property = 
     (PropertyInfo)((MemberExpression)propertySelector.Body).Member; 

    ParameterExpression parameter = Expression.Parameter(typeof(T)); 

    var expression = Expression.Lambda<Func<T, bool>>(
     Expression.Call(
      Expression.Constant(ids), 
      typeof(ICollection<int>).GetMethod("Contains"), 
      Expression.Property(parameter, property)), 
     parameter); 

    return entities.Where(expression); 
} 

, sık sık ifade ağaçları ile keman zorunda kalacak: Bu hile olacaktır. İşte another fun example.

+0

Fantastik. Http://blogs.msdn.com/b/miah/archive/2009/02/06/dynamic-expression-trees.aspx ve http://stackoverflow.com/questions/ adresinden ifade ağacının nasıl oluşturulacağını deniyordum. 820896/listobject-includes-expression-tree ancak Koleksiyon/Listeyi nasıl oluşturacağınızı anlayamadı. Teşekkür ederim! – David

+3

@DavidLiddle: Küçük bir sırrın içine girmene izin vereceğim: Ben sadece LINQ sorgusunu yazarım, derleyin ve C# derleyicisinin ne ürettiğini görmek için Reflektör'ü açın. Bu bilgiyi ayrıca hata ayıklayıcıda da görebilirsiniz, ancak Reflektör çok daha kolaydır. – Steven

+0

"Sadece LINQ sorgusunu yaz" ifadesine bir örnek verebilir misiniz? ILSpy'yi kullanarak sadece yazdığım LINQ sorgusunu görüyorum! – David