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. 【新架构测试】Fiddler转发数据测试

    跨域转发设置: 首先进行设置, AutoResponder--> 选中Enable rules和Unmatched requests passthrough 然后Import...导入fiddl ...

  2. scrapy 关于 rule, 关于多页

    分页 https://www.jianshu.com/p/0c957c57ae10 关于 follow=true, rule https://zhuanlan.zhihu.com/p/25650763 ...

  3. c++ STL中的set和multiset

    1.结构 set和multiset会根据特定的排序原则将元素排序.两者不同之处在于,multisets允许元素重复,而set不允许重复. set中的元素可以是任意类型的,但是由于需要排序,所以元素必须 ...

  4. GitHub使用笔记2:github常用操作

    1: 绑定ssh keys 2:github新建仓库 echo "# SpringStack" >> README.md git init git add README ...

  5. 头像上传uploadPreview插件

    原文链接:https://blog.csdn.net/Alisa_L/article/details/52923953 uploadPreview 今天写头像上传,使用到uploadPreview插件 ...

  6. 在C#中使用OpenCV(使用OpenCVSharp)

    在C#中使用OpenCV(使用OpenCVSharp) 1.什么是OpenCVSharp       为了解决在Csharp下编写OpenCV程序的问题,我做过比较深入的研究,并且实现了高效可用的方法 ...

  7. Ymodem协议(参考STM32)

    相信很多人都希望,不开盖就可以对固件进行升级吧,就像手机那些.下文中的bootload就来实现这样的功能. 前段时间有项目关于Bootload设计.所以就仔细的去了研究了一翻.以前都是用的stm32官 ...

  8. eMMC应用教程:关于RPMB的应用【转】

    本文转载自:https://blog.csdn.net/youdianhai/article/details/51246379 RPMB的意思是Replay Protected Memory Bloc ...

  9. Ubuntu 使用unzip解压乱码的问题

    由于win使用的是GBK编码,在win下打包zip的压缩文件在ubuntu下使用unzip解压会出现乱码的问题. 解决方案: 换软件,不用unzip,使用unar 18.04是默认安装的,如果没有默认 ...

  10. cmd使用管理员权限运行,启动路径不是当前目录

    https://stackoverflow.com/questions/672693/windows-batch-file-starting-directory-when-run-as-admin B ...