Entity Framework Core 实现全局查询过滤
微软在 Entity Framework Core 2+ 中引入了全局查询过滤器,简化了构建多租户应用程序和实体软删除的复杂度。这篇文章我将通过代码的形式对全局过滤查询进行详细的讲解。在讲解前我们先来简单说一下什么是多租户,所谓多租户简单来说是指一个单独的实例可以为多个组织服务。多租户技术为共用的数据中心内如何以单一系统架构与服务提供多数客户端相同甚至可定制化的服务,并且仍然可以保障客户的数据隔离。
接下来我们先来看一个例子,我们假定多个租户使用同一个数据库,同一个Schema,区分租户是根据表中的 tId 区分。我们新建一个项目,在项目中重写 DbContext 上下文里的 OnModelCreating 方法,在这个方法中我们使用 HasQueryFilter 方法进行软删除。
public class EFContext : DbContext
{protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<Employee>().HasQueryFilter(p => !p.IsDelete);modelBuilder.Entity<Department>().HasQueryFilter(p => !p.IsDelete);base.OnModelCreating(modelBuilder);}
}
我们首先准备 Model 代码,代码很简单:
/// <summary>
/// 实体基类
/// </summary>
public class BaseModel
{public int Id { get; set; }//租户Idpublic int TId { get; set; }//是否删除(软删除)public bool IsDelete { get; set; }
}
/// <summary>
/// 员工类
/// </summary>
public class Employee:BaseModel
{public string Name { get; set; }public int Age { get; set; }public Department Department { get; set; }
}
/// <summary>
/// 部门类
/// </summary>
public class Department:BaseModel
{public string DepName { get; set; }public int EmployeeId { get; set; }
}
public class EmployeeConfiguration : IEntityTypeConfiguration<Employee>
{public void Configure(EntityTypeBuilder<Employee> builder){builder.ToTable("Employee");builder.HasKey(p => p.Id);builder.Property(p => p.Name);builder.Property(p => p.IsDelete);builder.Property(p => p.Age);builder.HasQueryFilter(p => !p.IsDelete);}
}
public class DepartmentConfiguration : IEntityTypeConfiguration<Department>
{public void Configure(EntityTypeBuilder<Department> builder){builder.ToTable("Department");builder.HasKey(p => p.Id);builder.Property(p => p.DepName);builder.Property(p => p.IsDelete);builder.HasQueryFilter(p => !p.IsDelete);builder.HasMany(p => p.Employees).WithOne(e => e.Department).HasForeignKey(k => k.DepartmentId);}
}
public interface ITenantProvider
{int GetTId();
}
public class TenantProvider : ITenantProvider
{public int GetTId(){return 1;}
}
public interface IDepartmentDb
{IQueryable<Department> GetDepartments();
}
public class DepartmentDb : IDepartmentDb
{private EFContext ef;public DepartmentDb(EFContext _ef){ef = _ef;}public IQueryable<Department> GetDepartments(){var departments = ef.Departments;return departments;}
}
如果要为所有实体配置全局查询过滤器,就必须能够自动检测出实体类型,同时类型检测时必须具有缓存支持。基于这两条我们动手创建获取实体类型的接口和实现。首先利用 DependencyContext 获取运行时程序集,将获得的程序集添加到集合中,然后查找出继承自基类 BaseModel 的程序集,如果查找到了就返回,如果没有查找到就实现全局过滤缓存,代码如下:
public interface IEntityTypeProvider
{IEnumerable<Type> GetTypes();
}public class EntityTypeProvider : IEntityTypeProvider
{IList<Type> entityTypeCache;public IEnumerable<Type> GetTypes(){if(entityTypeCache!=null){return entityTypeCache.ToList();}entityTypeCache = (from a in GetReferencingAssemblies()from t in a.DefinedTypeswhere t.BaseType == typeof(BaseModel)select t.AsType()).ToList();return entityTypeCache;}private IEnumerable<Assembly> GetReferencingAssemblies(){var assemblies = new List<Assembly>();var dependencies = DependencyContext.Default.RuntimeLibraries;foreach (var library in dependencies){var assembly = Assembly.Load(new AssemblyName(library.Name));assemblies.Add(assembly);}return assemblies;}}
上一小节我们查找到了继承基类的所有实体,那么现在我们就将全局过滤器应用到实体。
第一步首先,获取租户 id 和前面对应的实现,并注入到上下文构造函数中:
public class EFContext : DbContext
{public DbSet<Employee> Employees;public DbSet<Department> Departments;protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.ApplyConfiguration(new EmployeeConfiguration());modelBuilder.ApplyConfiguration(new DepartmentConfiguration());base.OnModelCreating(modelBuilder);}private int tId;private IEntityTypeProvider entityTypeProvider;public EFContext(DbContextOptions<EFContext> options,ITenantProvider tenantProvider,IEntityTypeProvider entityTypeProvider):base(options){tId = tenantProvider.GetTId();this.entityTypeProvider = entityTypeProvider;}
}
public void GlobalQuery<T> (ModelBuilder builder) where T :BaseModel
{builder.Entity<T>().HasQueryFilter(e => e.TId == tId && !e.IsDelete);
}
static readonly MethodInfo GlobalQueryMethod = typeof(EFContext).GetMethods(BindingFlags.Public | BindingFlags.Instance).Single(p=>p.IsGenericMethod && p.Name== "GlobalQuery");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.ApplyConfiguration(new EmployeeConfiguration());modelBuilder.ApplyConfiguration(new DepartmentConfiguration());foreach (var item in entityTypeProvider.GetTypes()){var method = GlobalQueryMethod.MakeGenericMethod(item);method.Invoke(this, new object[] { modelBuilder });}base.OnModelCreating(modelBuilder);
}
这篇文章这是简单的实现了多租户和软删除,队医业务场景更加复杂的项目,我们需要利用一些特殊方法来实现全局查询过滤器。上面所说的方法只是其中一种,不排除由更好的方法。
【END】
Python的前景怎么样?就业薪资高吗?
https://edu.csdn.net/topic/python115?utm_source=csdn_bw
热 文 推 荐
Entity Framework Core 实现全局查询过滤相关推荐
- Entity Framework Core 2.0 全局查询过滤器
本博文翻译自: http://gunnarpeipman.com/2017/08/ef-core-global-query-filters/ Entity Framework Core 2.0 全局查 ...
- Entity Framework Core 2.0 特性介绍和使用指南
前言 这是.Net Core 2.0生态生态介绍的最后一篇,EF一直是我喜欢的一个ORM框架,随着版本升级EF也发展到EF6.x,Entity Framework Core是一个支持跨平台的全新版本, ...
- Entity Framework Core 5中实现批量更新、删除
本文介绍了一个在EntityFramework Core 5中不需要预先加载数据而使用一句SQL语句批量更新.删除数据的开发包,并且分析了其实现原理,并且与其他实现方案做了比较. 一.背景 随着微软全 ...
- 手把手引进门之 ASP.NET Core Entity Framework Core(官方教程翻译版 版本3.2.5)
以下是手把手引进门教程,基于 ASP.NET Core, Entity Framework Core ,ABP 框架 创建Web 应用, PS: 自带自动的测试模块哦. 样例下载 (上 github ...
- Entity Framework Core Like 查询揭秘
在Entity Framework Core 2.0中增加一个很酷的功能:EF.Functions.Like(),最终解析为SQL中的Like语句,以便于在 LINQ 查询中直接调用. 不过Entit ...
- Entity Framework Core 执行SQL语句和存储过程
无论ORM有多么强大,总会出现一些特殊的情况,它无法满足我们的要求.在这篇文章中,我们介绍几种执行SQL的方法. 表结构 在具体内容开始之前,我们先简单说明一下要使用的表结构. public clas ...
- Entity Framework Core 软删除与查询过滤器
注意:我使用的是 Entity Framework Core 2.0 (2.0.0-preview2-final).正式版发布后,功能可能存在变动. 继续探索Entity Framework Core ...
- 第一百五十二期:白话Entity Framework Core数据验证
数据验证是每个项目必须存在的,可以防止不符合系统规范的数据进入系统进而导致系统不稳定甚至崩溃.我们可以自己编写代码进行验证,但是这样一方面代码量较大,另一方面有可能验证代码覆盖不完全.但是在 Enti ...
- Entity Framework Core系列教程-25-Entity Framework Core日志
Entity Framework Core日志 我们经常需要在EF Core中记录SQL并更改跟踪信息以进行调试. EF Core日志记录自动与.NET Core的日志记录机制集成.因此,在隐含使用E ...
最新文章
- Oracle 11G在用EXP 导出时,空表不能导出解决
- 洛谷 1658 购物
- LINQ to XML .Net 3.5 中的新XML对象
- python获得当前目录_python如何获取当前工程根目录
- cf1562E. Rescue Niwen!
- golang plugin模块的使用
- oracle 监听拒绝连接,报mybatis映射文件错误Listener refused the connection with the following error: ORA-12519, TNS
- python3flask教程_全面的Flask教程[3大部分]
- 开放式可编程保险市场Tidal Finance完成由KR1领投的195万美元种子轮融资
- N沟道与P沟道增强型MOS管电压、原理、导通条件!
- 原神pc端服务器切换工具,基于python3
- 雅利安人覆灭了世界三大文明,为何单单在商朝被斩首两万?
- 后台Redirect,出现502错误
- 逻辑门电路工作原理详解
- 秒杀(小米网抢购系统开发实践--“米粉节”背后的故事)
- jQuery 特效:盒子破碎和移动动画效果
- Kitty中的动态线程池支持Nacos,Apollo多配置中心了
- SphereEx 潘娟:玩开源,我们就要秀出别样 My Way 来构建活力生态 | 大话开源Vol.11
- vba 抓取 统计用区划和城乡划分代码 到 电子表格
- 【附源码】计算机毕业设计SSM社区团购系统
热门文章
- LINQ TO OBJECT
- [ubuntu] 按文件大小进行排序
- python数字识别关键技术_用Python从零开始设计数字图片识别神经网络--搭建基本架构...
- python安装rarfile模块_python模块整理7-zipfile模块
- swiper 上滑触发_新知 | 为何红酒杯壁挂“眼泪”,骑自行车不会倒,冰面那么滑?...
- 记录——《C Primer Plus (第五版)》第八章编程练习第二题
- Flutter实战一Flutter聊天应用(十九)
- 5 大场景深度探讨何为 Serverless 架构模式?
- java中使用tika_Tika基本使用
- IE和Windows系统中的彩蛋