From 8edfd2f2ddd80a6e743229f75ca17cc725f807bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 18 Nov 2019 17:19:52 +0300 Subject: [PATCH] Added Defining Custom Filters section. --- docs/en/Data-Filtering.md | 104 +++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/docs/en/Data-Filtering.md b/docs/en/Data-Filtering.md index 78266c5dd8..4235d2f3e4 100644 --- a/docs/en/Data-Filtering.md +++ b/docs/en/Data-Filtering.md @@ -8,7 +8,7 @@ ABP defines some filters out of the box. ### ISoftDelete -Used to mark an entity as deleted instead of actually deleting it. Implement the `ISoftDelete` interface to make your entity "soft delete". +Used to mark an [entity](Entities.md) as deleted instead of actually deleting it. Implement the `ISoftDelete` interface to make your entity "soft delete". Example: @@ -119,4 +119,104 @@ Configure(options => }); ```` -> Carefully change defaults for global filters, especially if you are using a pre-built module which might be developed assuming the soft delete filter is turned on by default. But you can do it for your own defined filters safely. \ No newline at end of file +> Carefully change defaults for global filters, especially if you are using a pre-built module which might be developed assuming the soft delete filter is turned on by default. But you can do it for your own defined filters safely. + +## Defining Custom Filters + +Defining and implementing a new filter highly depends on the database provider. ABP implements all pre-defined filters for all database providers. + +When you need it, start by defining an interface (like `ISoftDelete` and `IMultiTenant`) for your filter and implement it for your entities. + +Example: + +````csharp +public interface IIsActive +{ + bool IsActive { get; } +} +```` + +Such an `IIsActive` interface can be used to filter active/passive data and can be easily implemented by any [entity](Entities.md): + +````csharp +public class Book : AggregateRoot, IIsActive +{ + public string Name { get; set; } + + public bool IsActive { get; set; } //Defined by IIsActive +} +```` + +### EntityFramework Core + +ABP uses [EF Core's Global Query Filters](https://docs.microsoft.com/en-us/ef/core/querying/filters) system for the [EF Core Integration](Entity-Framework-Core.md). So, it is well integrated to EF Core and works as expected even if you directly work with `DbContext`. + +Best way to implement a custom filter is to override `CreateFilterExpression` method for your `DbContext`. Example: + +````csharp +protected bool IsActiveFilterEnabled => DataFilter?.IsEnabled() ?? false; + +protected override Expression> CreateFilterExpression() +{ + var expression = base.CreateFilterExpression(); + + if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))) + { + Expression> isActiveFilter = + e => !IsActiveFilterEnabled || EF.Property(e, "IsActive"); + expression = expression == null + ? isActiveFilter + : CombineExpressions(expression, isActiveFilter); + } + + return expression; +} +```` + +* Added a `IsActiveFilterEnabled` property to check if `IIsActive` is enabled or not. It internally uses the `IDataFilter` service introduced before. +* Overrided the `CreateFilterExpression` method, checked if given entity implements the `IIsActive` interface and combines the expressions if necessary. + +### MongoDB + +ABP implements data filters directly in the [repository](Repositories.md) level for the [MongoDB Integration](MongoDB.md). So, it works only if you use the repositories properly. Otherwise, you should manually filter the data. + +Currently, the best way to implement a data filter for the MongoDB integration is to override the `AddGlobalFilters` in the repository derived from the `MongoDbRepository` class. Example: + +````csharp +public class BookRepository : MongoDbRepository +{ + protected override void AddGlobalFilters(List> filters) + { + if (DataFilter.IsEnabled()) + { + filters.Add(Builders.Filter.Eq(e => ((IIsActive)e).IsActive, true)); + } + } +} +```` + +This example implements it only for the `Book` entity. If you want to implement for all entities (those implement the `IIsActive` interface), create your own custom MongoDB repository base class and override the `AddGlobalFilters` as shown below: + +````csharp +public abstract class MyMongoRepository : MongoDbRepository + where TMongoDbContext : IAbpMongoDbContext + where TEntity : class, IEntity +{ + protected MyMongoRepository(IMongoDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + + } + + protected override void AddGlobalFilters(List> filters) + { + if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)) + && DataFilter.IsEnabled()) + { + filters.Add(Builders.Filter.Eq(e => ((IIsActive)e).IsActive, true)); + } + } +} +```` + +> See "Set Default Repository Classes" section of the [MongoDb Integration document](MongoDB.md) to learn how to replace default repository base with your custom class. \ No newline at end of file