14

Bir DbContext aracılığıyla her sorguya bir filtre eklemek için bir Entity Framework CommandTree engelleyicisi kullanmaya çalışıyorum.Entity Framework Interceptor'da İçine DbScanExpression Ekleme

Basitlik amacıyla, iki sütun ("UserId" ve "EmailAddress") ve "TenantUser" olarak adlandırılan iki sütun ("UserId" ve "TenantId") olarak adlandırılan iki tablo var. .

Her zaman Kullanıcı tablosunun DbScan'ı olduğunda, TenantUser tablosuna karşı bir iç birleştirme yapmak ve TenantId sütununu temel alarak filtre uygulamak istiyorum.

EntityFramework.Filters adlı bu proje, bu satırlarda bir şey yapan, ancak yapmaya çalıştığım gibi görünen "karmaşık birleşimleri" desteklemeyen bir proje var.

a demo from TechEd 2014'dan sonra, DbScanExpressions'ı bir DbJoinExpression ile değiştirmek için aşağıdaki yöntemle bir ziyaretçiyi kullanan bir önleme oluşturdum. Bu çalışmayı tamamladıktan sonra, bilinen bir ID ile TenantId sütununu karşılaştırmak için bir DbFilterExpression'a sarmayı planlıyorum.

public override DbExpression Visit(DbScanExpression expression) 
    { 
     var table = expression.Target.ElementType as EntityType; 
     if (table != null && table.Name == "User") 
     { 
      return DbExpressionBuilder.InnerJoin(expression, DbExpressionBuilder.Scan(expression.Target), (l, r) => 
       DbExpressionBuilder.Equal(DbExpressionBuilder.Variable(tenantUserIdProperty.TypeUsage, "UserId"), 
        DbExpressionBuilder.Variable(userIdProperty.TypeUsage, "UserId"))); 
     } 

     return base.Visit(expression); 
    } 

yukarıdaki kodu test etmek için, ben DBContext için önleme eklendi ve aşağıdaki kodu çalıştırın ettik:

No property with the name 'EmailAddress' is declared by the type 'Transient.rowtype[(l,CodeFirstDatabaseSchema.User(Nullable=True,DefaultValue=)),(r,CodeFirstDatabaseSchema.User(Nullable=True,DefaultValue=))]'.

:

dbContext.Users.Select(u => new { u.EmailAddress }).ToList(); 

Ancak bu aşağıdaki hatası

DbJoinExpression'u yanlış mı yapıyorum? Yoksa başka bir şey mi özlüyorum?

cevap

3

Bu istisnayı elde etmenizin sebebi, InnerJoin'in her iki tablonun sütunlarını bir araya getirmesi ve diğer yandan da sorgulamanın, sınıf kullanıcısının bu eşleşen özelliklerini döndürmesi gerektiği için olmasından kaynaklanır. sorgu

public override DbExpression Visit(DbScanExpression expression) 
{ 
    var table = expression.Target.ElementType as EntityType; 
    if (table != null && table.Name == "User") 
    { 
     return expression.InnerJoin(
      DbExpressionBuilder.Scan(expression.Target.EntityContainer.BaseEntitySets.Single(s => s.Name == "TennantUser")), 
      (l, r) => 
       DbExpressionBuilder.Equal(
        DbExpressionBuilder.Property(l, "UserId"), 
        DbExpressionBuilder.Property(r, "UserId") 
       ) 
     ) 
     .Select(exp => 
      new { 
       UserId = exp.Property("l").Property("UserId"), 
       Email = exp.Property("l").Property("Email") 
      }); 
    } 

    return base.Visit(expression); 
} 

sen sonra birleşim koşulu belirterek ifadeden onun lambda ifadesi diğer adını kullanarak belirli katıldı tabloya bakın operasyonuna katılmak bkz gibi: İşte benim için çalıştı kodudur. Bu yüzden benim durumumda, Kullanıcı tablosuna l ve TennantUser'e r olarak başvurursunuz. L ve r harflerinin yanı sıra veritabanına gönderilen SQL sorgusunda takma adlar kullanılacaktır. InnerJoin ve Seç operasyonlar arasında size bu tam olarak ne gerekli olduğunu vb

+0

Filtre gibi gereken ek mantığı yerleştirebilir. Çok teşekkürler! –

+0

Benim cevabım bunun bir faydası olmayacağını müteessir :) Ama belki ileride birileri sizin için bir "bit" çok geç muhtemelen geldi. – mr100

+0

Bu taramaların yazılmasını kolaylaştırmak için Ziyaretçi'ye düzenli bir İfadede bir yol var mı? – AndrewP