How to use Global Filter at EntityFramework Core ?
Global filter, ef ile linq sorguları yazarken yazdığımız filtreyi otomatik ekleyen bir özelliktir. Genelllik softdelete gibi durumlarda kullanılsa da birçok ihtiyaca cevap veriyor.
Aşağıdaki entity üzerinden örnek kullanımlarını inceleyeceğiz.
Product.cs
1 2 3 4 5 6 7 8 9 10 11 |
public class Product: ISoftDelete,ISortableEntity { public int Id { get; set; } public string Name { get; set; } = ""; public int CategoryId { get; set; } public bool MyProperty { get; set; } public bool IsDeleted { get ; set; } public int? Order { get; set ; } public virtual Category Category { get; set; } } |
IsDeleted ve Order alanları ISoftDelete ve ISortableEntity interfacelerinden türüyor.
Temel Kullanımı
Product için GlobalFilter Kullanımını HasQueryFilters
aracılığıyla yapıyoruz.
1 |
modelBuilder.Entity<Product>().HasQueryFilter(p => !p.IsDeleted); |
Aşağıdaki sorguyu çalıştıralım ve generate edilen sorguya bakalım.
1 |
var result = dbContext.Products.AsEnumerable(); |
Result:
1 2 3 |
SELECT [p].[Id], [p].[CategoryId], [p].[ExpireDate], [p].[IsDeleted], [p].[Name], [p].[Order], [p].[Price] FROM [Products] AS [p] WHERE [p].[IsDeleted] = CAST(0 AS bit) |
Gördüğünüz gibi bir koşul eklememize rağmen global olarak eklediğimiz IsDeleted
filter eklenmiş oldu.
Önemli Not:
Aynı Entity için birden çok query filter oluşturamazsınız fakat query içinde and ve or operatörleriyle birden çok oluşturabilirsiniz.
Navigation Propertyler (İlişkili Alanlar)
İlişkili alanlar için de ekleme yapabilirsiniz.
1 |
modelBuilder.Entity<Product>().HasQueryFilter(p => p.Category.Name == "Console"); |
Sorgu:
var result = dbContext.Products.AsEnumerable();
Sonuç (As Sql)
1 2 3 4 |
SELECT [p].[Id], [p].[CategoryId], [p].[ExpireDate], [p].[IsDeleted], [p].[Name], [p].[Order], [p].[Price] FROM [Products] AS [p] INNER JOIN [Categories] AS [c] ON [p].[CategoryId] = [c].[Id] WHERE [c].[Name] = N'Console' |
Burada dikkat etmemiz gerek şey, Include yapmamıza rağmen query filterın bunu uygulaması.
Disable
Bazı sorgularda global filter iptal etme ihtiyacı olabilir bu durumlar için IgnoreQueryFilters operatörünü kullanabiliriz.
1 |
var result = dbContext.Products.IgnoreQueryFilters().AsEnumerable(); |
Sonuç:
1 2 |
SELECT [p].[Id], [p].[CategoryId], [p].[ExpireDate], [p].[IsDeleted], [p].[Name], [p].[Order], [p].[Price] FROM [Products] AS [p] |
Ortak Kullanılan Alanlar İçin Genel Bir Query Oluşturma
Yukarıdaki örnekte softdelete alanlar için hepsine tek tek yazmamız gerekiyor, bundan kurtarmak için aşağıdaki çözümü kullanabiliriz.
1 2 3 4 5 6 7 8 |
Expression<Func<ISoftDelete, bool>> filterExpr = x => !x.IsDeleted; foreach (var mutableEntityType in modelBuilder.Model.GetEntityTypes()) { var parameter = Expression.Parameter(mutableEntityType.ClrType); var body = ReplacingExpressionVisitor.Replace(filterExpr.Parameters.First(), parameter, filterExpr.Body); var lambdaExpression = Expression.Lambda(body, parameter); mutableEntityType.SetQueryFilter(lambdaExpression); } |
Okuduğunuz için teşekkürler, başka bir gönderide görüşmek üzere 🙂