扩展EF的Fluent API中的 OnModelCreating方法 实现全局数据过滤器
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方法 实现全局数据过滤器的更多相关文章
- Web Api中实现Http方法(Put,Post,Delete)
在Web Api中实现Http方法(Put,Post,Delete) 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我 ...
- EF Core Fluent API
多对多配置 先安装 Install-Package MySql.Data.EntityFrameworkCore 创建3个表 创建类 public class Role { public long I ...
- 一步一步学EF系列1【Fluent API的方式来处理实体与数据表之间的映射关系】
EF里面的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面,还有一个就是F ...
- 第六节:框架搭建之EF的Fluent Api模式的使用流程
一. 前言 沉寂了约一个月的时间,今天用一篇简单的文章重新回归博客,主要来探讨一下Fluent Api模式在实际项目中的使用流程. 1. Fluent API属于EF CodeFirst模式的一种,E ...
- 一步一步学EF系列二【Fluent API的方式来处理实体与数据表之间的映射关系】
EF里面的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面,还有一个就是F ...
- 第十八篇 .NET高级技术之Linq与EF Code-First Fluent API基础讲解
1.FluentApi简介 在这里提供了一个fluentapi基础的DEMO然后咱们在进一步的学习,直接上干货. 第一步在数据库创建一个表:person 第二步:新建控制台程序FluentAPI 第三 ...
- EF:Fluent API 把一对多映射为一对一
假设有两张表:A表和B表.A表与B表在数据库中的关系是一对多,但我们需要在EF中映射为一对一. 首先在A实体类和B实体类中互相为对方增加一个实体类的属性: public A { public B B ...
- 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)
系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现——Post(新 ...
- EF使用Fluent API配置映射关系
定义一个继承自EntityTypeConfiguration<>泛型类的类来定义domain中每个类的数据库配置,在这个自定义类的构造函数中使用我们上次提到的那些方法配置数据库的映射. 映 ...
随机推荐
- Makefile shell subst $(1)
MAKE_3_80_realpath = $(shell $(top_srcdir)/scripts/realpath.sh '$(subst $(SQUOTE),\\$(SQUOTE),$(1 ...
- shell 冒号
: ${TEST_LOOP:='1'} 如果不在前面加上:(冒号)命令,那么就会把${TEST_LOOP:='1'}本身当做一个命令来执行,报错是肯定的. [root@node56 ~]# : abc ...
- corn
http://www.cnblogs.com/itech/archive/2011/02/09/1950226.html service crond start ---查看crontab服务是否启动 ...
- JVM的垃圾回收机制
JVM的垃圾回收机制:(GC通过确定对象是否被活动对象引用来确定是否收集该对象.) 1.触发GC(Garbage Collector)的条件. (1.GC在优先级最低的线程中运行,在未运行的线程中进行 ...
- 两步完成ssh免密码登录
1.生成公钥/私钥 ssh-keygen -N '' 生成公钥在/root/.ssh目录下. 2.分发公钥 ssh-copy-id root@192.168.137.141 192.168.137.1 ...
- 获取RadioButton选中的值
1.RadioButtonList的RepeatDirection="Horizontal"可以设置按扭选项横对齐: 2.获取选中的RadioButton值; $("#& ...
- 公网FTP(filezilla)改端口
背景:我们如果不修改ftp服务器的端口,很容易被别人测试和攻击. 配置要点:服务端端口设置.主被动设置.服务端和客户端防火墙设置 ftp服务器:filezilla ftp server 1. 监听端 ...
- 20145208 蔡野 《网络对抗》Exp6 信息搜集与漏洞扫描
20145208 蔡野 <网络对抗>Exp6 信息搜集与漏洞扫描 本实践的目标是掌握信息搜集的最基础技能.具体有(1)各种搜索技巧的应用(2)DNS IP注册信息的查询 (3)基本的扫描技 ...
- 剑指offer(31)1~n整数中1出现的次数
题目描述 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了. ...
- 回归Android之Android基础和小常识
Activity ,Service,Content Provider,BroadcastReceiver, Intent SQLite,Http,Fragement,Handle 1,Activity ...