5

Bazı kodları daha okunabilir hale getirmeye çalışıyorum ve uzantı yöntemini ve/veya ifadesini nasıl yapılandıracağımı tam olarak anlamadım. Şu anda üzerlerinde RecordStatusTypeId burada amacım açabiliyorum .ActiveRecords()LINQ - Varlıklar yöntemi (ilgili bir varlıkta) tanımayan

gibi bir uzantı yöntemi ile .Where(RecordStatusTypeId != (int)RecordStatusTypes.Deleted) gibi bir ifade değiştirmektir

public interface IRecordStatus 
{ 
    int RecordStatusTypeId { get; set; } 
    RecordStatusType RecordStatusType { get; set; } 
} 

(IRecordStatus bir arayüzden uygulanan) olan birçok varlıklara sahip aşağıdaki uzatma yöntemi ile Bunu gerçekleştirmek için:

public static IQueryable<T> ActiveRecords<T>(this DbSet<T> entitySet) 
    where T : class, IRecordStatus 
{ 
    return entitySet.Where(e => e.RecordStatusTypeId != (int)RecordStatusTypes.Deleted); 
} 
Ben DbSet<T> için bu uzantı yöntemine sahip *

, IQueryable<T>, ICollection<T> ve IEnumerable<T>

Bu MyDbContext.Entities.Where(e => e.RecordStatusTypeId != (int)RecordStatusTypes.Deleted) gibi ifadeleri için çok çalışır, ama ben hatayı ben gibi bir şey değiştirmeye çalışırsanız "varlıkları için LINQ yöntemini tanımıyor" olsun: Ben ne

MyDbContext.Entities.Where(e => e.RelatedEntity.Where(re => re.RecordStatusTypeId != (int)RecordStatusTypes.Deleted)); 

yapmak istiyorum: Ben DbSet yanı sıra bir linq maddesi içinde ilgili varlık üzerinde aktif kayıtları için filtre böylece

MyDbContext.Entities.Where(e => e.RelatedEntity.ActiveRecords().Any()); 

nasıl Uzatma Yöntemleri değiştirmek (veya bir İfade ekleyin) olabilir?

+0

Entity Framework Plus bunu yapabilir: https://github.com/zzzprojects/EntityFramework-Plus –

+0

@CyrilIselin, Teşekkürler, ben kontrol edeceğim. –

+1

Yönteminiz T-SQL'e çevrilemiyor, Varlıkların Linq tarafından tanınması mümkün değil. 'AsEnumerable' öğesini' Entities''e ekleyin ve tekrar deneyin: 'MyDbContext.Entities.AsEnumerable(). Where ...'. –

cevap

2

Dönüşümünüzü yanlış yapmış olabilirsiniz. Gerekir: Buna

MyDbContext.Entities.Where(e => e.RelatedEntity.Where(re => re.RecordStatusTypeId != (int)RecordStatusTypes.Deleted)); 

dönüştürme:

MyDbContext.Entities.Where(e => e.RelatedEntity.ActiveRecords().Any()); 
+0

Evet, haklısınız. Ne yazık ki, bu sadece yazıyı sadeleştirmeye çalışan bölümümde bir hataydı. Soruyu çözdüm. –

1

Queryable.Where SQL tercüme edilebilir bir ifade beklediği çünkü istisna alıyorsanız ve ActiveRecords SQL için tercüme edilemez.

Yapmanız gereken şey, aramayınumaralı aramayı genişletmek için .Where(e => e.RecordStatusTypeId != (int)RecordStatusTypes.Deleted numaralı aramaya genişletme ifadesini güncellemektir.

Çalışan bir çözüm için taslak sunacağım. Sağladığınız örneğe çok özgüdür. Jenerik yapmak için muhtemelen üzerinde çalışmalısınız.

aşağıdaki ifade ziyaretçi temelde bir argüman olarak uygun bir deyimle Where çağrısına ActiveRecords çağrısını değişecektir:

public class MyVisitor : ExpressionVisitor 
{ 
    protected override Expression VisitMethodCall(MethodCallExpression m) 
    { 
     if (m.Method.Name == "ActiveRecords") 
     { 
      var entityType = m.Method.GetGenericArguments()[0]; 
      var whereMethod = genericWhereMethod.MakeGenericMethod(entityType); 

      var param = Expression.Parameter(entityType); 
      var expressionToPassToWhere = 
       Expression.NotEqual(
        Expression.Property(param, "RecordStatusTypeId"), 
        Expression.Constant((int)RecordStatusTypes.Deleted)); 

      Expression newExpression = 
       Expression.Call(
        whereMethod, 
        m.Arguments[0], 
        Expression.Lambda(
         typeof(Func<,>).MakeGenericType(entityType, typeof(bool)), 
         expressionToPassToWhere, 
         param)); 

      return newExpression; 
     } 

     return base.VisitMethodCall(m); 
    } 

    //This is reference to the open version of `Enumerable.Where` 
    private static MethodInfo genericWhereMethod; 

    static MyVisitor() 
    { 
     genericWhereMethod = typeof (Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static) 
      .Where(x => x.Name == "Where" && x.GetGenericArguments().Length == 1) 
      .Select(x => new {Method = x, Parameters = x.GetParameters()}) 
      .Where(x => x.Parameters.Length == 2 && 
         x.Parameters[0].ParameterType.IsGenericType && 
         x.Parameters[0].ParameterType.GetGenericTypeDefinition() == typeof (IEnumerable<>) && 
         x.Parameters[1].ParameterType.IsGenericType && 
         x.Parameters[1].ParameterType.GetGenericTypeDefinition() == typeof (Func<,>)) 
      .Select(x => x.Method) 
      .Single(); 
    } 
} 

Daha sonra geçirmeden önce ifadesini ziyaret etmek için özel WhereSpecial yöntemi oluşturabilirsiniz Queryable gerçek Where yöntemine:

public static class ExtentionMethods 
{ 
    public static IQueryable<T> WhereSpecial<T>(this IQueryable<T> queryable, Expression<Func<T,bool>> expression) 
    { 
     MyVisitor visitor = new MyVisitor(); 

     var newBody = visitor.Visit(expression.Body); 

     expression = expression.Update(newBody, expression.Parameters); 

     return queryable.Where(expression); 
    } 
} 

Ve sonra bunları gibi kullanabilirsiniz:

var result = MyDbContext.Entities.WhereSpecial(e => e.RelatedEntity.ActiveRecords().Any()); 
+0

Tüm bu yenilikleri ilk etapta yardımcısı ActiveRecords yöntemini kullanmanın tüm amacını yapıyor gibi görünüyor :) – Evk

+0

@Evk, bu muhtemelen doğrudur :) Belki de yöntem isimleri ve karşılık gelen lambda ifadeleri bir sözlük alır daha genel bir ziyaretçi yapar Bunların hepsini yapmaya değer. –

+0

@YacoubMassad, Böyle bir şeyin çabaya değip değmeyeceğini araştırmak için zamanım olmadı, ama cevabınız için teşekkür ederim. Tekrar ziyaret için zamanım olduğunda güncellemeye döneceğim. –

0

IQueryable sorgusunun ana bölümünü oluşturmaya çalışın, sonra nerede bulunduğunuzu etiketleyin ...gibi

şey:

IQueryable temp = from x in MyDbContext.Entities 
        select x; 

temp = temp.Where(e => e.RelatedEntity.ActiveRecords().Any()); 

veya ana bölümünü değerlendirmek ve daha sonra bellekte yerde gerçekleştirin.

+0

Öneriniz için teşekkürler, ancak bu arabirim çeşitli nesne nesnelerine uygulandığından, ActiveRecords için filtrelemeden (en azından hiç değilse), sorgunun içeriğini geri çekemiyorum. –