EntityFramework Core Global Filter Kullanımı
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 🙂