EF Core 中实现 动态数据过滤器

前言

  在项目开发中,我们很多时候都会设计  软删除、所属用户 等等一系列字段 来方便我们在业务查询的时候进行各种过滤

  然后引申的问题就是:

    在业务查询的时候,我们要如何加上这些条件?或者动态禁用某些查询条件呢?

EF Core自带的全局过滤查询功能

  EF Core提供了一个HasQueryFilter 供我们在查询的时候进行预置部分筛选条件

  例如:

      builder.HasQueryFilter(x => !x.IsDelete);

  这样查询的时候  EF Core 会自动帮我们实现过滤

  然后如果不想使用的时候可以全部忽略

    DbSet.IgnoreQueryFilters();

  咋一看 很完美

  然后我们实际操作的时候

  1.我是不是每个Entity里面是不是都要配置一次呢?

  2.我只想禁用部分筛选条件呢?

  3.我的查询条件的某些参数要动态呢?

    例如和用户相关的数据等等

    (有些人可能会说 我想办法把User的信息注入到DbContext里面不就可以了  假如我还要别的信息呢  还是接着注入?)

  这就是理论和实践之间的差距

  然后再网上找好久,找到了 EntityFramework-Plus  (开源免费)

  https://github.com/zzzprojects/EntityFramework-Plus

     官网地址: http://entityframework-plus.net/  

  内置了很多功能  本篇只针对查询过滤做说嘛

EntityFramework-Plus 查询过滤功能

  1.QueryFilterManager

  QueryFilterManager 主要用来预设全局过滤

  例如:

  QueryFilterManager.Filter<Customer>(q => q.Where(x => x.IsActive));

  var ctx = new EntitiesContext();

  QueryFilterManager.InitilizeGlobalFilter(ctx);

  这样即可。。。

  但是需要提前注意的是 QueryFilterManager 预设后是无法更改的

  无法更改这是在  谷歌的时候  作者正好回复的别人的时候看到的

  就和我们之前第三点  动态 冲突了

  然后只能再看别的方式了

  2.Filter

  Z.EntityFramework.Plus 提供了 通过DbContext 的扩展方式来进行注入筛选条件的方式

  例如:

  var ctx = new EntitiesContext();

  ctx.Filter<IAnimal>(MyEnum.EnumValue, q => q.Where(x => x.IsDomestic))

  //禁用指定键值查询条件

  ctx.Filter(MyEnum.EnumValue).Disable();

  var dogs = ctx.Dogs.ToList();

  //启用指定键值查询条件

  ctx.Filter(MyEnum.EnumValue).Enable();

  // SELECT * FROM Dog WHERE IsDomestic = true
  var dogs = ctx.Dogs.ToList();

  这样好像符合我们的需求

  3.AsNoFilter

  禁用条件

  例如: 

  var ctx = new EntitiesContext();

  this.Filter<Customer>(q => q.Where(x => x.IsActive));

  // SELECT * FROM Customer WHERE IsActive = true
  var list = ctx.Customers.ToList();

  // SELECT * FROM Customer
  var list = ctx.Customers.AsNoFilter().ToList();

  AsNoFilter()后如何启用  指定查询条件  作者好像没有做相应扩展 ,后面会给出对应扩展方法

-----------------------------------------------------------------------------------------------------------------------------------------------------------

说了这么多 理论补完了   实际操作的时候呢?

  1.这些条件如何注入进来呢?

  2.如何可以让我任意扩展呢?

     3.假如我们操作时通过仓储 ,而不是  直接通过DbContext 呢?

如何封装

这边演示通过我自己的开源项目做为事例:

  github  : https://github.com/wulaiwei/WorkData.Core

  主要依赖的框架

  1.AutoFac

  2.EF Core

  3.Z.EntityFramework.Plus

-----------------------------------------------------------------------------------------------------------------------------------------  

  对于我们来说 我们无论使用多少个数据筛选器  返回的都应该是同一个返回值  ,我们去看 DbContext.Filter(....)  会发现他的返回值都是 BaseQueryFilter

  针对这个  我们可以得到两条信息  我们需要 传入 DbContext  和 一个返回值为  BaseQueryFilter  的方法

  所以 我们定义如下接口 IDynamicFilter

1     public interface IDynamicFilter
2     {
3         BaseQueryFilter InitFilter(DbContext dbContext);
4     }

  这样我们这边就得到了一个标准

  例如 我们我们需要一个 所属用户和  软删除 的数据筛选器   我们只需要继承他即可

  我们如何区分他们呢?

  我们在之前使用 Z.EntityFramework.Plus  是看到了  可以设置筛选器的Key

  所以 我们也同样扩展个属性 DynamicFilterAttribute  来作为他们的名字

1     public class DynamicFilterAttribute: Attribute
2     {
3         /// <summary>
4         /// Name
5         /// </summary>
6         public string Name { get; set; }
7
8     }

  然后我们定义我们的  所属用户和  软删除 的数据筛选器  并为他们设置名称

  CreateDynamicFilter

 1  /// <summary>
 2     /// CreateDynamicFilter
 3     /// </summary>
 4     [DynamicFilter(Name = "CreateUserId")]
 5     public class CreateDynamicFilter : IDynamicFilter
 6     {
 7         /// <summary>
 8         /// InitFilter
 9         /// </summary>
10         /// <param name="dbContext"></param>
11         /// <returns></returns>
12         public BaseQueryFilter InitFilter(DbContext dbContext)
13         {
14             var workdataSession = IocManager.Instance.Resolve<IWorkDataSession>();
15             if (workdataSession == null)
16                 return dbContext
17                     .Filter<ICreate>("CreateUserId", x => x.Where(w => w.CreateUserId == string.Empty ));
18
19             return dbContext
20                 .Filter<ICreate>("CreateUserId", x => x.Where(w => w.CreateUserId == workdataSession.UserId || w.CreateUserId == ""));
21         }
22     }

  说明:

  var workdataSession = IocManager.Instance.Resolve<IWorkDataSession>();

  用来获取你所需要的 传参

  IocManager.Instance.Resolve  是WorkData  关于Ioc的封装  源码可以参见git  或者上一篇博客

  SoftDeleteDynamicFilter

 1 /// <summary>
 2     /// SoftDeleteDynamicFilter
 3     /// </summary>
 4     [DynamicFilter(Name = "SoftDelete")]
 5     public class SoftDeleteDynamicFilter: IDynamicFilter
 6     {
 7         public BaseQueryFilter InitFilter(DbContext dbContext)
 8         {
 9             return dbContext
10                 .Filter<IsSoftDelete>("SoftDelete", x => x.Where(w => !w.IsDelete));
11         }
12     }

   这样 我们所有接口 和实现定义好了 如何管理呢?

  1.将继承 IDynamicFilter 的注入到Ioc里面

 1             #region 动态审计注入
 2             var filterTypes = _typeFinder.FindClassesOfType<IDynamicFilter>();
 3
 4             foreach (var filterType in filterTypes)
 5             {
 6                 var dynamicFilterAttribute = filterType.GetCustomAttribute(typeof(DynamicFilterAttribute)) as DynamicFilterAttribute;
 7                 if (dynamicFilterAttribute == null)
 8                     continue;
 9
10                 builder.RegisterType(filterType).Named<IDynamicFilter>(dynamicFilterAttribute.Name);
11             }
12             #endregion

  说明:

  1.ITypeFinder 是从 nopcommerce 抽离出来的反射方法   已集成到WorkData  百度即可查询到相应说明文档

  2.通过 GetCustomAttribute  获取 DynamicFilterAttribute 的属性名称  作为注册到Ioc名称

  2.如何设置一个启用数据筛选器呢?我们这边定义个配置文件  通过 .net core 提供的程序进行配置文件注入

1     /// <summary>
2     /// 动态拦截器配置
3     /// </summary>
4     public class DynamicFilterConfig
5     {
6         public List<string> DynamicFilterList{ get; set; }
7     }

"DynamicFilterConfig": {

"DynamicFilterList": [ "CreateUserId", "SoftDelete" ]
}

如何注入配置文件 可以通过百度或者查看workdata源码 即可 这不做说明

  3.如何管理呢?什么时候统一添加到 DbContext呢?

  我们这边定义一个DynamicFilterManager 提供一个 字典集合 来暂存所以的 IDynamicFilter,同时提供一个方法来进行初始化值

 1     public static class DynamicFilterManager
 2     {
 3         static DynamicFilterManager()
 4         {
 5             CacheGenericDynamicFilter = new Dictionary<string, IDynamicFilter>();
 6         }
 7
 8         /// <summary>
 9         ///     CacheGenericDynamicFilter
10         /// </summary>
11         public static Dictionary<string, IDynamicFilter> CacheGenericDynamicFilter { get; set; }
12
13         /// <summary>
14         ///     AddDynamicFilter
15         /// </summary>
16         /// <param name="dbContext"></param>
17         /// <returns></returns>
18         public static void AddDynamicFilter(this DbContext dbContext)
19         {
20             if (dbContext == null) return;
21             foreach (var dynamicFilter in CacheGenericDynamicFilter) dynamicFilter.Value.InitFilter(dbContext);
22         }
23
24         /// <summary>
25         ///     AsWorkDataNoFilter
26         /// </summary>
27         /// <typeparam name="T"></typeparam>
28         /// <param name="query"></param>
29         /// <param name="context"></param>
30         /// <param name="filterStrings"></param>
31         /// <returns></returns>
32         public static IQueryable<T> AsWorkDataNoFilter<T>(this DbSet<T> query, DbContext context,
33             params object[] filterStrings) where T : class
34         {
35             var asNoFilterQueryable = query.AsNoFilter();
36
37             object query1 = asNoFilterQueryable;
38             var items = CacheGenericDynamicFilter.Where(x => filterStrings.Contains(x.Key));
39
40             query1 = items.Select(key => context.Filter(key.Key)).Where(item => item != null)
41                 .Aggregate(query1, (current, item) => (IQueryable) item.ApplyFilter<T>(current));
42             return (IQueryable<T>) query1;
43         }
44
45         /// <summary>
46         ///     SetCacheGenericDynamicFilter
47         /// </summary>
48         public static void SetCacheGenericDynamicFilter()
49         {
50             var dynamicFilterConfig = IocManager.Instance.ResolveServiceValue<DynamicFilterConfig>();
51
52             foreach (var item in dynamicFilterConfig.DynamicFilterList)
53             {
54                 var dynamicFilter = IocManager.Instance.ResolveName<IDynamicFilter>(item);
55                 CacheGenericDynamicFilter.Add(item, dynamicFilter);
56             }
57         }
58     }

  然后我们在DbContext里面的 OnModelCreating 进行初始化

 1  /// <summary>
 2         ///     重写模型创建函数
 3         /// </summary>
 4         /// <param name="modelBuilder"></param>
 5         protected override void OnModelCreating(ModelBuilder modelBuilder)
 6         {
 7             base.OnModelCreating(modelBuilder);
 8
 9             //初始化对象
10             DynamicFilterManager.SetCacheGenericDynamicFilter();
11         }

  初始化完成后如何将条件付给  DbContext 呢?

  在DynamicFilterManager 中我们提供了一个扩展方法 AddDynamicFilter 你可以在你创建 DbContext 的时候调用

 1      /// <summary>
 2         ///     AddDynamicFilter
 3         /// </summary>
 4         /// <param name="dbContext"></param>
 5         /// <returns></returns>
 6         public static void AddDynamicFilter(this DbContext dbContext)
 7         {
 8             if (dbContext == null) return;
 9             foreach (var dynamicFilter in CacheGenericDynamicFilter) dynamicFilter.Value.InitFilter(dbContext);
10         }

  在WorkData中  我们则需要在EfContextFactory 进行调用

  dbContext = _resolver.Resolve<TDbContext>();

  //初始化拦截器
  dbContext.AddDynamicFilter();

 1   /// <summary>
 2     ///     EfContextFactory
 3     /// </summary>
 4     public class EfContextFactory : IEfContextFactory
 5     {
 6         private readonly IResolver _resolver;
 7
 8         public EfContextFactory(IResolver resolver)
 9         {
10             _resolver = resolver;
11         }
12
13         /// <summary>
14         ///     default current context
15         /// </summary>
16         /// <param name="dic"></param>
17         /// <param name="tranDic"></param>
18         /// <returns></returns>
19         public TDbContext GetCurrentDbContext<TDbContext>(Dictionary<string, DbContext> dic, Dictionary<DbContext, IDbContextTransaction> tranDic)
20             where TDbContext : DbContext
21         {
22             return GetCurrentDbContext<TDbContext>(dic, tranDic, string.Empty);
23         }
24
25         /// <summary>
26         ///GetCurrentDbContext
27         /// </summary>
28         /// <typeparam name="TDbContext"></typeparam>
29         /// <param name="dic"></param>
30         /// <param name="tranDic"></param>
31         /// <param name="conString"></param>
32         /// <returns></returns>
33         public TDbContext GetCurrentDbContext<TDbContext>(Dictionary<string, DbContext> dic, Dictionary<DbContext, IDbContextTransaction> tranDic, string conString)
34             where TDbContext : DbContext
35         {
36             conString = typeof(TDbContext).ToString();
37             var dbContext = dic.ContainsKey(conString + "DbContext") ? dic[conString + "DbContext"] : null;
38             try
39             {
40                 if (dbContext != null)
41                 {
42                     return (TDbContext)dbContext;
43                 }
44             }
45             catch (Exception)
46             {
47                 dic.Remove(conString + "DbContext");
48             }
49             dbContext = _resolver.Resolve<TDbContext>();
50
51             //初始化拦截器
52             dbContext.AddDynamicFilter();
53
54             //我们在创建一个,放到数据槽中去
55             dic.Add(conString + "DbContext", dbContext);
56
57             //开始事务
58             var tran = dbContext.Database.BeginTransaction();
59             tranDic.Add(dbContext, tran);
60
61             return (TDbContext)dbContext;
62         }
63     }

  这样我们的筛选器已经全部注入完成了

  还剩下一个我们之前说的

  AsNoFilter()后如何启用  指定查询条件  作者好像没有做相应扩展 ,后面会给出对应扩展方法

  通过查看源码后 

 1     /// <summary>
 2     ///     Filter the query using context filters associated with specified keys.
 3     /// </summary>
 4     /// <typeparam name="T">The type of elements of the query.</typeparam>
 5     /// <param name="query">The query to filter using context filters associated with specified keys.</param>
 6     /// <param name="keys">
 7     ///     A variable-length parameters list containing keys associated to context filters to use to filter the
 8     ///     query.
 9     /// </param>
10     /// <returns>The query filtered using context filters associated with specified keys.</returns>
11     public static IQueryable<T> Filter<T>(this DbSet<T> query, params object[] keys) where T : class
12     {
13       BaseQueryFilterQueryable filterQueryable = QueryFilterManager.GetFilterQueryable((IQueryable) query);
14       IQueryable<T> query1 = filterQueryable != null ? (IQueryable<T>) filterQueryable.OriginalQuery : (IQueryable<T>) query;
15       return QueryFilterManager.AddOrGetFilterContext(filterQueryable != null ? filterQueryable.Context : InternalExtensions.GetDbContext<T>(query)).ApplyFilter<T>(query1, keys);
16     }

Z.EntityFramework.Plus  提供了一个 ApplyFilter  所以 我们基于这个 做个扩展

 1   /// <summary>
 2         ///     AsWorkDataNoFilter
 3         /// </summary>
 4         /// <typeparam name="T"></typeparam>
 5         /// <param name="query"></param>
 6         /// <param name="context"></param>
 7         /// <param name="filterStrings"></param>
 8         /// <returns></returns>
 9         public static IQueryable<T> AsWorkDataNoFilter<T>(this DbSet<T> query, DbContext context,
10             params object[] filterStrings) where T : class
11         {
12             var asNoFilterQueryable = query.AsNoFilter();
13
14             object query1 = asNoFilterQueryable;
15             var items = CacheGenericDynamicFilter.Where(x => filterStrings.Contains(x.Key));
16
17             query1 = items.Select(key => context.Filter(key.Key)).Where(item => item != null)
18                 .Aggregate(query1, (current, item) => (IQueryable) item.ApplyFilter<T>(current));
19             return (IQueryable<T>) query1;
20         }

这样 我们可以传入指定的筛选器名称  启用自己想要的

最终我们的仓储就变成了这样:

  1  /// <summary>
  2     ///     EfBaseRepository
  3     /// </summary>
  4     /// <typeparam name="TEntity"></typeparam>
  5     /// <typeparam name="TPrimaryKey"></typeparam>
  6     /// <typeparam name="TDbContext"></typeparam>
  7     public class EfBaseRepository<TDbContext, TEntity, TPrimaryKey> :
  8         BaseRepository<TEntity, TPrimaryKey>,
  9         IRepositoryDbConntext where TEntity : class, IAggregateRoot, IEntity<TPrimaryKey>
 10         where TDbContext : DbContext
 11     {
 12         //public IQueryable<EntityType> EntityTypes => Context.Model.EntityTypes.Where(t => t.Something == true);
 13
 14         private readonly IDbContextProvider<TDbContext> _dbContextProvider;
 15         private readonly IPredicateGroup<TEntity> _predicateGroup;
 16
 17         public EfBaseRepository(
 18             IDbContextProvider<TDbContext> dbContextProvider,
 19             IPredicateGroup<TEntity> predicateGroup)
 20         {
 21             _dbContextProvider = dbContextProvider;
 22             _predicateGroup = predicateGroup;
 23         }
 24
 25         /// <summary>
 26         ///     Gets EF DbContext object.
 27         /// </summary>
 28         public TDbContext Context => _dbContextProvider.GetContent();
 29
 30         /// <summary>
 31         ///     Gets DbSet for given entity.
 32         /// </summary>
 33         public virtual DbSet<TEntity> DbSet => Context.Set<TEntity>();
 34
 35         #region DbContext
 36
 37         /// <summary>
 38         ///     GetDbContext
 39         /// </summary>
 40         /// <returns></returns>
 41         public DbContext GetDbContext()
 42         {
 43             return Context;
 44         }
 45
 46         #endregion
 47
 48         #region Query
 49
 50
 51
 52         /// <summary>
 53         ///     FindBy
 54         /// </summary>
 55         /// <param name="primaryKey"></param>
 56         /// <returns></returns>
 57         public override TEntity FindBy(TPrimaryKey primaryKey)
 58         {
 59             var entity = DbSet.Find(primaryKey);
 60             return entity;
 61         }
 62
 63         /// <summary>
 64         /// FindBy
 65         /// </summary>
 66         /// <param name="primaryKey"></param>
 67         /// <param name="includeNames"></param>
 68         /// <returns></returns>
 69         public override TEntity FindBy(TPrimaryKey primaryKey, string[] includeNames)
 70         {
 71             var query = DbSet;
 72             foreach (var includeName in includeNames)
 73             {
 74                 query.Include(includeName);
 75             }
 76             var entity = query.Find(primaryKey);
 77             return entity;
 78         }
 79
 80         /// <summary>
 81         ///     AsNoFilterFindBy
 82         /// </summary>
 83         /// <param name="primaryKey"></param>
 84         /// <returns></returns>
 85         public override TEntity AsNoFilterFindBy(TPrimaryKey primaryKey)
 86         {
 87             var entity = DbSet.AsNoFilter()
 88                 .SingleOrDefault(x => x.Id.Equals(primaryKey));
 89             return entity;
 90         }
 91
 92         /// <summary>
 93         /// AsNoFilterFindBy
 94         /// </summary>
 95         /// <param name="primaryKey"></param>
 96         /// <param name="includeNames"></param>
 97         /// <returns></returns>
 98         public override TEntity AsNoFilterFindBy(TPrimaryKey primaryKey, string[] includeNames)
 99         {
100
101             var query = DbSet.AsNoFilter();
102             foreach (var includeName in includeNames)
103             {
104                 query.Include(includeName);
105             }
106             var entity = query.SingleOrDefault(x => x.Id.Equals(primaryKey));
107
108             return entity;
109         }
110
111
112         /// <summary>
113         ///     FindBy
114         /// </summary>
115         /// <param name="primaryKey"></param>
116         /// <param name="filterStrings"></param>
117         /// <returns></returns>
118         public override TEntity FindBy(TPrimaryKey primaryKey, params object[] filterStrings)
119         {
120             var entity = DbSet.AsWorkDataNoFilter(Context, filterStrings)
121                 .SingleOrDefault(x => x.Id.Equals(primaryKey));
122             return entity;
123         }
124
125         /// <summary>
126         /// FindBy
127         /// </summary>
128         /// <param name="primaryKey"></param>
129         /// <param name="includeNames"></param>
130         /// <param name="filterStrings"></param>
131         /// <returns></returns>
132         public override TEntity FindBy(TPrimaryKey primaryKey, string[] includeNames, params object[] filterStrings)
133         {
134             var query = DbSet.AsWorkDataNoFilter(Context, filterStrings);
135             foreach (var includeName in includeNames)
136             {
137                 query.Include(includeName);
138             }
139             var entity = query.SingleOrDefault(x => x.Id.Equals(primaryKey));
140
141             return entity;
142         }
143
144
145         /// <summary>
146         ///     GetAll
147         /// </summary>
148         /// <returns></returns>
149         public override IQueryable<TEntity> GetAll()
150         {
151             return DbSet;
152         }
153
154
155         /// <summary>
156         /// GetAll
157         /// </summary>
158         /// <param name="includeNames"></param>
159         /// <returns></returns>
160         public override IQueryable<TEntity> GetAll(string[] includeNames)
161         {
162             var query = DbSet;
163             foreach (var includeName in includeNames)
164             {
165                 query.Include(includeName);
166             }
167             return query;
168         }
169
170         /// <summary>
171         /// GetAll
172         /// </summary>
173         /// <param name="filterStrings"></param>
174         /// <returns></returns>
175         public override IQueryable<TEntity> GetAll(params object[] filterStrings)
176         {
177             return DbSet.AsWorkDataNoFilter(Context, filterStrings);
178         }
179
180         /// <summary>
181         /// GetAll
182         /// </summary>
183         /// <param name="includeNames"></param>
184         /// <param name="filterStrings"></param>
185         /// <returns></returns>
186         public override IQueryable<TEntity> GetAll(string[] includeNames, params object[] filterStrings)
187         {
188             var query = DbSet.AsWorkDataNoFilter(Context, filterStrings);
189
190             foreach (var includeName in includeNames)
191             {
192                 query.Include(includeName);
193             }
194             return query;
195         }
196
197         /// <summary>
198         /// AsNoFilterGetAll
199         /// </summary>
200         /// <returns></returns>
201         public override IQueryable<TEntity> AsNoFilterGetAll()
202         {
203             return DbSet.AsNoFilter();
204         }
205
206         /// <summary>
207         /// AsNoFilterGetAll
208         /// </summary>
209         /// <param name="includeNames"></param>
210         /// <returns></returns>
211         public override IQueryable<TEntity> AsNoFilterGetAll(string[] includeNames)
212         {
213             var query = DbSet.AsNoFilter();
214
215             foreach (var includeName in includeNames)
216             {
217                 query.Include(includeName);
218             }
219             return query;
220         }
221         #endregion
222
223         #region Insert
224
225         /// <summary>
226         ///     Insert
227         /// </summary>
228         /// <typeparam name="TEntity"></typeparam>
229         /// <param name="model"></param>
230         public override TEntity Insert(TEntity model)
231         {
232             return DbSet.Add(model).Entity;
233         }
234
235         /// <summary>
236         ///     InsertGetId
237         /// </summary>
238         /// <param name="model"></param>
239         /// <returns></returns>
240         public override TPrimaryKey InsertGetId(TEntity model)
241         {
242             model = Insert(model);
243
244             Context.SaveChanges();
245
246             return model.Id;
247         }
248
249         /// <summary>
250         ///     Insert
251         /// </summary>
252         /// <param name="entities"></param>
253         public override void Insert(IEnumerable<TEntity> entities)
254         {
255             if (entities == null)
256                 throw new ArgumentNullException(nameof(entities));
257
258             DbSet.AddRange(entities);
259
260             Context.SaveChanges();
261         }
262
263         #endregion
264
265         #region Delete
266
267         /// <summary>
268         ///     Delete
269         /// </summary>
270         /// <param name="entity"></param>
271         public override void Delete(TEntity entity)
272         {
273             DbSet.Remove(entity);
274             Context.SaveChanges();
275         }
276
277         /// <summary>
278         ///     Delete
279         /// </summary>
280         /// <param name="entities"></param>
281         public override void Delete(IEnumerable<TEntity> entities)
282         {
283             if (entities == null)
284                 throw new ArgumentNullException(nameof(entities));
285
286             DbSet.RemoveRange(entities);
287
288             Context.SaveChanges();
289         }
290
291         #endregion
292
293         #region Update
294
295         /// <summary>
296         ///     Update
297         /// </summary>
298         /// <param name="entity"></param>
299         public override void Update(TEntity entity)
300         {
301             DbSet.Update(entity);
302             Context.SaveChanges();
303         }
304
305         /// <summary>
306         ///     Update
307         /// </summary>
308         /// <param name="entities"></param>
309         public override void Update(IEnumerable<TEntity> entities)
310         {
311             if (entities == null)
312                 throw new ArgumentNullException(nameof(entities));
313
314             DbSet.UpdateRange(entities);
315
316             Context.SaveChanges();
317         }
318
319         #endregion
320     }

  说明:仓储的设计理念是从  ABP中抽离出来的 

  最后附测试  

启用的筛选器为 "CreateUserId", "SoftDelete"

 1  /// <summary>
 2         ///     Index
 3         /// </summary>
 4         /// <returns></returns>
 5         public IActionResult Index()
 6         {
 7             _baseRepository.GetAll().ToList();
 8             _baseRepository.GetAll("CreateUserId","xxx假定不存在的筛选器").ToList();
 9             _baseRepository.AsNoFilterGetAll().ToList();
10
11             _baseRepository.FindBy("1");
12             _baseRepository.FindBy("1", "CreateUserId", "xxx假定不存在的筛选器");
13             _baseRepository.AsNoFilterFindBy("1");
14             return View();
15         }

原文地址:https://www.cnblogs.com/wulaiwei/p/9561830.html

时间: 2024-10-03 18:58:39

EF Core 中实现 动态数据过滤器的相关文章

EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery

一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文,可以返货DbConnection ,执行sql语句.这是最底层的操作方式,代码写起来还是挺多的. 初次之外 EF Core中还支持 FromSql,ExecuteSqlCommand 连个方法,用于更方便的执行Sql语句. 另外,目前版本的EF Core 不支持SqlQuery,但是我们可以自己扩

EF Core 中DbContext不会跟踪聚合方法和Join方法返回的结果

EF Core中: 如果调用Queryable.Count等聚合方法,不会导致DbContext跟踪(track)任何实体. 此外调用Queryable.Join方法返回的匿名类型也不会被DbContext所跟踪(实测调用Queryable.Join方法返回EF Core中的实体类型也不会被DbContext所跟踪). Queryable.Count等聚合方法和Queryable.Join方法返回的结果不会被跟踪,原因是因为这两种方法返回的结果类型并没有被DbContext的OnModelCre

ASP.NET Core中使用自定义MVC过滤器属性的依赖注入

原文:ASP.NET Core中使用自定义MVC过滤器属性的依赖注入 除了将自己的中间件添加到ASP.NET MVC Core应用程序管道之外,您还可以使用自定义MVC过滤器属性来控制响应,并有选择地将它们应用于整个控制器或控制器操作. ASP.NET Core中常用的MVC过滤器之一是  ExceptionFilterAttribute,用于处理Wep API应用程序中的错误响应.它很容易实现,开发人员和我在ASP.NET Core中使用MVC过滤器属性所面临的问题是访问Startup.cs类

EF Core中如何设置数据库表自己与自己的多对多关系

本文的代码基于.NET Core 3.0和EF Core 3.0 有时候在数据库设计中,一个表自己会和自己是多对多关系. 在SQL Server数据库中,现在我们有Person表,代表一个人,建表语句如下: CREATE TABLE [dbo].[Person]( [PersonID] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](50) NULL, [Age] [int] NULL, CONSTRAINT [PK_Person] PRIMARY

浅谈如何使用python抓取网页中的动态数据

我们经常会发现网页中的许多数据并不是写死在HTML中的,而是通过js动态载入的.所以也就引出了什么是动态数据的概念, 动态数据在这里指的是网页中由Javascript动态生成的页面内容,是在页面加载到浏览器后动态生成的,而之前并没有的. 在编写爬虫进行网页数据抓取的时候,经常会遇到这种需要动态加载数据的HTML网页,如果还是直接从网页上抓取那么将无法获得任何数据. 今天,我们就在这里简单聊一聊如何用python来抓取页面中的JS动态加载的数据. 给出一个网页:豆瓣电影排行榜,其中的所有电影信息都

EF Core中的DB First与Code First

前言: 大家都习惯在程序中生成对应的model来对数据库进行操作,所以如何快速的生成数据库表的对应model,是基础之一.总结了一下在我的认知中大概是这个结构: Db first方式: 先创建好对应的数据库通过数据库来生成对应的Model. 1 创建数据库 大家可根据自己的需要生成对应的数据库,这里只做演示所以使用官方给的SqlServer数据库脚本: CREATE DATABASE [Blogging]; GO USE [Blogging]; GO CREATE TABLE [Blog] (

jsp中使用动态数据进行mySQL数据库的两种操作方法

使用动态数据进行数据库内容的增删改查操作有两种方法: 在此定义数据库连接为conn 假设有表单进行数据输入并提交到处理页面一种是使用预编译格式: 其格式如下: String name = request.getParameter("name");//获取前页表单中name为name的值 String password = request.getParameter("password");//获取前页表单中name为password的值 String sql = &q

ef core中如何实现多对多的表映射关系

文档:https://docs.microsoft.com/en-us/ef/core/modeling/relationships class MyContext : DbContext { public DbSet<Post> Posts { get; set; } public DbSet<Tag> Tags { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { m

EF Core中DeleteBehavior的介绍(转自MSDN)

Delete behaviors Delete behaviors are defined in the DeleteBehavior enumerator type and can be passed to the OnDelete fluent API to control whether the deletion of a principal/parent entity or the severing of the relationship to dependent/child entit