1.生成过滤的表达式目录树

        protected virtual Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
where TEntity : class
{
//构建的表达式目录树 TEntity就是满足条件的每个实体表
Expression<Func<TEntity, bool>> expression = null; //根据租户ID进行过滤数据
//expression = e => ((ILonsidEntity)e).TenantId == LonsidSession.TenantId; // TEntity类型是否继承ISoftDelete
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
//过滤出所有没有被软删除的记录
Expression<Func<TEntity, bool>> softDeleteFilter = e => !((ISoftDelete)e).IsDeleted;
//如果当前表达式为Null 就赋值 如果不为null 就把两个表达式组合
expression = expression == null ? softDeleteFilter : CombineExpressions(expression, softDeleteFilter);
} if (typeof(IMayHaveTenant).IsAssignableFrom(typeof(TEntity)))
{
/* This condition should normally be defined as below:
* !IsMayHaveTenantFilterEnabled || ((IMayHaveTenant)e).TenantId == CurrentTenantId
* But this causes a problem with EF Core (see https://github.com/aspnet/EntityFrameworkCore/issues/9502)
* So, we made a workaround to make it working. It works same as above.
*/
Expression<Func<TEntity, bool>> mayHaveTenantFilter = e => ((IMayHaveTenant)e).TenantId == CurrentTenantId || (((IMayHaveTenant)e).TenantId == CurrentTenantId) == IsMayHaveTenantFilterEnabled;
expression = expression == null ? mayHaveTenantFilter : CombineExpressions(expression, mayHaveTenantFilter);
} if (typeof(IMustHaveTenant).IsAssignableFrom(typeof(TEntity)))
{
/* This condition should normally be defined as below:
* !IsMustHaveTenantFilterEnabled || ((IMustHaveTenant)e).TenantId == CurrentTenantId
* But this causes a problem with EF Core (see https://github.com/aspnet/EntityFrameworkCore/issues/9502)
* So, we made a workaround to make it working. It works same as above.
*/
Expression<Func<TEntity, bool>> mustHaveTenantFilter = e => ((IMustHaveTenant)e).TenantId == CurrentTenantId || (((IMustHaveTenant)e).TenantId == CurrentTenantId) == IsMustHaveTenantFilterEnabled;
expression = expression == null ? mustHaveTenantFilter : CombineExpressions(expression, mustHaveTenantFilter);
} return expression;
}

2.配置全局过滤器   将表达式目录树添加进来

        private void ConfigureFilters<TEntity>(ModelBuilder modelBuilder, IMutableEntityType entityType)
where TEntity : class, ILonsidEntity
{
//entityType是否继承了ILonsidEntity
//这里应该不用这个判断 泛型 TEntity 已经有了约束条件 继承了ILonsidEntity
if (typeof(ILonsidEntity).IsAssignableFrom(entityType.ClrType))
{
//创建过滤的表达式目录树
var filterExpression = CreateFilterExpression<TEntity>();
if (filterExpression != null)
{
//将表达式引用到当前实体的任何查询中
modelBuilder.Entity<TEntity>().HasQueryFilter(filterExpression);
}
}
}

3.获取过滤方法

        //通过反射获取当前DbConText中的  配置的全局过滤器方法    这个过滤方法是私有的    要加BindingFlags.NonPublic
private static MethodInfo ConfigureFiltersMethodInfo = typeof(IMSDbContext).GetMethod(nameof(ConfigureFilters), BindingFlags.Instance | BindingFlags.NonPublic);

4.CRUD的时候执行过滤操作

        protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//先调用父类的方法
base.OnModelCreating(modelBuilder);
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
//所有继承ILonsidEntity的实体类都需要添加自定义的全局过滤器
if (typeof(ILonsidEntity).IsAssignableFrom(entityType.ClrType))
{
ConfigureFiltersMethodInfo
.MakeGenericMethod(entityType.ClrType)
.Invoke(this, new object[] { modelBuilder, entityType });
}
}
}

*************************************

动态是否使用租户进行过滤的写法

                Expression<Func<TEntity, bool>> mayHaveTenantFilter = e => ((IMayHaveTenant)e).TenantId == CurrentTenantId || (((IMayHaveTenant)e).TenantId == CurrentTenantId) == IsMayHaveTenantFilterEnabled;
((IMayHaveTenant)e).TenantId == CurrentTenantId 前半句已经固定好了  一定会进行过滤租户      

关于后半句IsMayHaveTenantFilterEnabled默认为true  开启租户过滤
(((IMayHaveTenant)e).TenantId == CurrentTenantId) == IsMayHaveTenantFilterEnabled;
1. 如果IsMayHaveTenantFilterEnabled为true 开启过滤
当前数据库中的行满足(((IMayHaveTenant)e).TenantId == CurrentTenantId) 为true 后半句就为true
                                     为false 后半句就为false
  前半句跟后半句的真假性相同  只有租户相等的才会查询出来

2.如果IsMayHaveTenantFilterEnabled为false 禁用过滤
  当前数据库中的行满足(((IMayHaveTenant)e).TenantId == CurrentTenantId) 会给查询出来
  当前数据库中的行不满足(((IMayHaveTenant)e).TenantId == CurrentTenantId) 表达式查询条件变成 false || false == false 后半句永远为true 所以不会进行数据过滤
结论:
IsMayHaveTenantFilterEnabled 为 true  表达式 前半句跟后半句真假性相同  只查询数据行满足租户ID
IsMayHaveTenantFilterEnabled 为false  表达式 前半句跟后半句真假性相反  所有数据库行都满足这个where 条件

												

扩展EF的Fluent API中的 OnModelCreating方法 实现全局数据过滤器的更多相关文章

  1. Web Api中实现Http方法(Put,Post,Delete)

    在Web Api中实现Http方法(Put,Post,Delete) 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我 ...

  2. EF Core Fluent API

    多对多配置 先安装 Install-Package MySql.Data.EntityFrameworkCore 创建3个表 创建类 public class Role { public long I ...

  3. 一步一步学EF系列1【Fluent API的方式来处理实体与数据表之间的映射关系】

    EF里面的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面,还有一个就是F ...

  4. 第六节:框架搭建之EF的Fluent Api模式的使用流程

    一. 前言 沉寂了约一个月的时间,今天用一篇简单的文章重新回归博客,主要来探讨一下Fluent Api模式在实际项目中的使用流程. 1. Fluent API属于EF CodeFirst模式的一种,E ...

  5. 一步一步学EF系列二【Fluent API的方式来处理实体与数据表之间的映射关系】

    EF里面的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面,还有一个就是F ...

  6. 第十八篇 .NET高级技术之Linq与EF Code-First Fluent API基础讲解

    1.FluentApi简介 在这里提供了一个fluentapi基础的DEMO然后咱们在进一步的学习,直接上干货. 第一步在数据库创建一个表:person 第二步:新建控制台程序FluentAPI 第三 ...

  7. EF:Fluent API 把一对多映射为一对一

    假设有两张表:A表和B表.A表与B表在数据库中的关系是一对多,但我们需要在EF中映射为一对一. 首先在A实体类和B实体类中互相为对方增加一个实体类的属性: public A { public B B ...

  8. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现——Post(新 ...

  9. EF使用Fluent API配置映射关系

    定义一个继承自EntityTypeConfiguration<>泛型类的类来定义domain中每个类的数据库配置,在这个自定义类的构造函数中使用我们上次提到的那些方法配置数据库的映射. 映 ...

随机推荐

  1. Tomcat配置Manager管理员

    修改文件: D:\MyDev\Tomcat\apache-tomcat-7.0.68\conf\tomcat-users.xml  配置内容: <role rolename="mana ...

  2. Piggy-Bank HDU - 1114

    Before ACM can do anything, a budget must be prepared and the necessary financial support obtained. ...

  3. 用WPE+CCproxy+自动代理截取安卓游戏封包

    wpe三件套:https://pan.baidu.com/s/19gI2GPZ0iuu4wpKljCOn4A 用WPE+CCproxy+自动代理截取安卓游戏封包>>

  4. DBeaver连接Oracle11g数据库

    DBeaver连接Oracle11g数据库 一.准备 (1)dbeaver管理软件 (2)远程连接数据库地址.用户名秘密等 (3)Oracle驱动:ojdbc6.jar工具包 下载地址:https:/ ...

  5. gnats配置文件

    尽管NATS可以无配置的运行,但也可以使用配置文件配置NATS服务器 1. 配置项包括 客户端监听器端口 Client listening port HTTP监听器端口 HTTP monitoring ...

  6. 关于innodb_flush_log_at_trx_commit、innodb_flush_method、innodb_log_block_size和fsync()、O_DIRECT、iops、云盘的关系与总结

    想着整理关于innodb_flush_log_at_trx_commit.innodb_flush_method.innodb_log_block_size和fsync().O_DIRECT.iops ...

  7. PHP获取Linux当前目录下文件并实现下载功能

    使用nginx转发过去给php server{ listen 9099; server_name 18.5.6.2; location / { proxy_http_version 1.1; root ...

  8. python简说(七)元组,集合

    一.元组 元组也是一个list,但是它的值不能改变 定义元组的时候,只有一个元素,后面得加逗号 oracle_info = (123,) 二.集合 1.集合天生就可以去重,集合是无序的 2.#交集 r ...

  9. [c/c++] programming之路(5)、吓人小程序、变量、进制等

    一.设计一个吓人的东西 首先创建MFC项目(勾选“基于对话框”后点击完成即可) 添加三个按钮 双击按钮进入响应代码段 void CMFCWindowsDlg::OnBnClickedButton1() ...

  10. Python-制作抖音图片

    ---------------------------------------------------------------------------------------------------- ...