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引入了全局查询过滤器,可以在创建模型时应用到实体 。它使得构建多租户应用程序和支持对实体 的软删除变得更加容易。这篇博客文章提供了关于如何在实际应用中使用全局查询过滤器的更深入的概述,以及如何将全局查询过滤器自动应用到领域实体。

示例解决方案。 我在 ASP.NET Core 2中构建了示例解决方案EFCoreGlobalQueryFilters 在更复杂的上下文中演示了全局查询过滤器。它演示了如何自动地将全局查询过滤器应用到领域实体。创建简单的数据库并使用sql脚本填充测试数据。

How global query filters look like?

全局查询过滤器是什么?

这就是全局查询筛选器在软删除时的样子。我们在DbContext类中重写了OnModelCreating方法。


protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<Playlist>().HasKey(e => e.Id);modelBuilder.Entity<Playlist>().HasQueryFilter(e => !e.IsDeleted);modelBuilder.Entity<Song>().HasKey(e => e.Id);modelBuilder.Entity<Song>().HasQueryFilter(e => !e.IsDeleted); base.OnModelCreating(modelBuilder);
}

这些过滤器,会在我们对给定类型的实体进行查询时应用

真正的应用程序需要什么?

上面的代码是简化的,不考虑实际的应用场景。但是应用程序的体系结构通常是复杂的。所以当我们考虑到作为数字核心或企业一部分任务的关键的应用程序时,创建的将不仅仅是几个类。本文的目标是演示以下内容:

  • 如何支持多租户

  • 如何支持软删除实体

  • 如何自动检测实体

示例解决方案 有助于我们从更复杂的场景开始,但它没有提供完全灵活和复杂的框架。当涉及到现实生活中的应用程序时,涉及的问题太多了,而每个应用程序通常都有自己的解决方案,以解决不同的问题。

定义实体

让我们从定义一些实体开始。他们使用简单的基类,并且期望所有的实体都从基类扩展。


public abstract class BaseEntity{    
  public int Id { get; set; }  
   public Guid TenantId { get; set; }
    public bool IsDeleted { get; set; } } public class Playlist : BaseEntity{    
    public string Title { get; set; } public IList<Song> Songs { get; set; } } public class Song : BaseEntity{  
      public string Artist { get; set; }  
        public string Title { get; set; }  
         public string Location { get; set; } }

现在我们有一些简单的实体了,是时候对多租户和软删除的实体进行下一步操作了。

租户提供者

在讨论多租户之前,web应用程序必须有某种方式来检测与当前请求相关的租户。它可以是基于host的header检测,但也可以是别的东西。在这篇文章中我们使用虚拟的提供者以便于我们提供简单的示例。


public interface ITenantProvider{   
 Guid GetTenantId(); } public class DummyTenantProvider : ITenantProvider{  
  public Guid GetTenantId()    {      
    return Guid.Parse("069b57ab-6ec7-479c-b6d4-a61ba3001c86");} }

这个提供者必须在启动类的ConfigureServices方法中注册。

创建数据上下文

我希望在这一点上,已经创建了这个数据库,并配置了应用程序来使用它,好了现在让我们从支持租户提供程序的简单数据上下文开始


public class PlaylistContext : DbContext{   
   private Guid _tenantId;  
   private readonly IEntityTypeProvider _entityTypeProvider;
  public virtual DbSet<Playlist> Playlists { get; set; }  
  public virtual DbSet<Song> Songs { get; set; }
  public PlaylistContext(DbContextOptions<PlaylistContext> options,                            ITenantProvider tenantProvider)        : base(options)    {_tenantId = tenantProvider.GetTenantId();}   protected override void OnModelCreating(ModelBuilder modelBuilder)  
  
{modelBuilder.Entity<Playlist>().HasKey(e => e.Id);modelBuilder.Entity<Song>().HasKey(e => e.Id); base.OnModelCreating(modelBuilder);}       }

现在我们有了可操作的context和租户ID,那么接下来我们就可以对自动创建的全局查询过滤器进行下一步操作了。

检测实体类型

在为所有实体类型添加全局查询过滤器之前,必须检测实体类型。如果我们知道基本实体类型,那么就很容易读取这些类型。但是有一个问题-model是建立在每个请求之上的,而我们每次在创建model时都要扫描程序集,显然这并不是一个好主意。因此,类型检测必须支持某种类型的缓存。下面示例中的这两个方法用于数据上下文类。


private static IList<Type> _entityTypeCache;

private static IList<Type> GetEntityTypes(){  
 if(_entityTypeCache != null){      
  return _entityTypeCache.ToList();}_entityTypeCache = (from a in GetReferencingAssemblies()                        from t in a.DefinedTypes              
         where t.BaseType
== typeof(BaseEntity)                        select t.AsType()).ToList(); return _entityTypeCache; }
  private static IEnumerable<Assembly> GetReferencingAssemblies(){  
    var assemblies = new List<Assembly>();     var dependencies = DependencyContext.Default.RuntimeLibraries; foreach (var library in dependencies){      
      try{        
         var assembly = Assembly.Load(new AssemblyName(library.Name));assemblies.Add(assembly);
         }   
        catch (FileNotFoundException){
        }}  
         return assemblies; }

警告! 如果有单独的服务来返回实体类型,那么在体系结构方面可以更好地理解。在上面的代码中,可以直接使用实体类型变量,而更糟糕的是,可以调用GetReferencingAssemblies方法。如果您编写真正的应用程序,那么最好使用单独的提供程序。

现在,数据上下文知道实体类型,并且可以编写一些代码来获得适用于所有实体的查询过滤器。

将查询过滤器应用于所有实体

这听起来很容易做,但事实并非如此。有些实体类型的列表,并没有直接使用方便的通用方法。在这一点上,需要一个小技巧。我从CodeDump页面找到了解决方案EF-Core 2.0 过滤所有查询 (并试图实现软删除). 这里的代码不能使用,因为这里的数据上下文对ITenantProvider有实例级的依赖关系。但要点仍然是相同的:让我们为数据上下文中的一些通用方法创建通用方法调用。


protected override void OnModelCreating(ModelBuilder modelBuilder){    foreach (var type in GetEntityTypes())   
 
{ var method = SetGlobalQueryMethod.MakeGenericMethod(type);method.Invoke(this, new object[]
{ modelBuilder });} base.OnModelCreating(modelBuilder); }
static readonly MethodInfo SetGlobalQueryMethod = typeof(PlaylistContext).GetMethods(BindingFlags.Public | BindingFlags.Instance).Single(t => t.IsGenericMethod && t.Name == "SetGlobalQuery");
public void SetGlobalQuery<T>(ModelBuilder builder) where T : BaseEntity {builder.Entity<T>().HasKey(e => e.Id);  //Debug.WriteLine("Adding global query for: " + typeof(T));builder.Entity<T>().HasQueryFilter(e => e.TenantId == _tenantId && !e.IsDeleted); }

这不是一种简单直观的代码。甚至当我看着这段代码时,我也会瞪大眼睛。即使我看了上百遍,它仍然看起来很疯狂和笨拙。SetGlobalQuery方法也是为实体定义主键的好地方,因为它们都是从相同的基础实体类继承而来的。

测试驱动

如果我们想要了解全局查询过滤器是如何工作的,我们可以使用样例应用程序中的HomeController 来实现这一点。


public class HomeController : Controller{   
 private readonly PlaylistContext _context;
   public HomeController(PlaylistContext context)    {_context = context;}
   public IActionResult Index()    {    
       var playlists = _context.Playlists.OrderBy(p => p.Title); return View(playlists);} }

我修改了默认视图,以显示查询返回的所有播放列表。


@model IEnumerable<Playlist><div class="row">    <div class="col-lg-8">        <h2>Playlists</h2>        <table class="table table-bordered">            <thead>                <tr>                    <th>Playlist</th>                    <th>Tenant ID</th>                    <th>Is deleted</th>                </tr>            </thead>            <tbody>                @foreach(var playlist in Model)                {                    <tr>                        <td>@playlist.Title</td>                        <td>@playlist.TenantId</td>                        <td>@playlist.IsDeleted</td>                    </tr>                }            </tbody>        </table>    </div></div>

Web应用程序现在可以运行了。下面是我使用的示例数据。让我们记住,示例应用程序使用的租户ID是069b57ab-6ec7-479c-b6d4-a61ba3001c86。

当运行web应用程序时,将显示下面的表。

当我们比较这两个表时,我们会很容易发现全局查询过滤器在工作中给出的预期结果。

结束

全局查询过滤器是Entity Framework Core 2.0的完美补充,如果没有很多实体,那么我们可以通过文档中给出的简单示例来实现。在更复杂的情况下,需要一些复杂的代码来自动应用全局查询过滤器。希望将来会有更好的解决方案,但目前这里给出的解决方案也做得很好。

相关文章: 

  • Entity Framework Core 2.0 新特性

  • EF Core 插件 —— ToSql

  • Entity Framework Core 执行SQL语句和存储过程

  • Entity Framework Core 批处理语句

  • Entity Framework Core 命名约定

  • Entity Framework Core 软删除与查询过滤器

  • Entity Framework Core 生成跟踪列

  • 在Apworks数据服务中使用基于Entity Framework Core的仓储(Repository)实现

  • Entity Framework Core的贴心:优雅处理带默认值的数据库字段

原文地址:http://www.cnblogs.com/chen-jie/p/ef-core-global-query-filters.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324062.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloudGateway

文章目录SpringCloudGateway起步消费端整合SpringCloudGateway静态路由配置内置扩展网关过滤内置网关过滤自定义过滤全局过滤器内置全局过滤器自定义全局过滤器ForwardRoutingFilterNetty全局路由响应式负载均衡代理GatewayMetricsFilter网关度量过滤器&#xff08;服务监控&am…

来自一位家长的肺腑之言,句句在理!!!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。今天分享一段话&#xff0c;原创来自三班的一位同学家长&#xff0c;可所谓字字在理&#xff01;看完之后我自己也反思了好多&#xff0c;主要是思想观念的转变&#xff0c;就像佟老师给我说的一样…

jzoj1295,P1607-轻轨(庙会班车)【贪心,线段树】

前言 我考试时敲了一个不仅比正解编程复杂度高&#xff0c;而且时间更慢&#xff0c;还AC不了的费用流 垃圾代码 #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define MN 20011 using namespace std; struct node{int…

一篇文章了解RPC框架原理

转载自 一篇文章了解RPC框架原理 1.RPC框架的概念 RPC&#xff08;Remote Procedure Call&#xff09;–远程过程调用&#xff0c;通过网络通信调用不同的服务&#xff0c;共同支撑一个软件系统&#xff0c;微服务实现的基石技术。使用RPC可以解耦系统&#xff0c;方便维护…

winform分页案例简单实现方式~

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。最近&#xff0c;四班在做KTV点歌系统&#xff0c;正好需要用到分页的内容&#xff0c;所以今天我就整理整理&#xff0c;写了一个简易的winfrom分页案例&#xff0c;以下是案例截图&#…

.Net Core下通过Proxy 模式 使用 WCF

.NET Core下的WCF客户端也是开源的&#xff0c;这次发布.NET Core 2.0,同时也发布了 WCF for .NET Core 2.0.0, 本文介绍在.NET Core下如何通过Proxy 消费WCF服务。 我们现在直接可以在 standard 2.0下调用wcf服务了&#xff0c;不过 Microsoft WCF Web Service Reference Pro…

JWT 入门

文章目录使用JWT的原因JWT结构JWT入门案例Token拦截使用JWT的原因 为了保护项目之中的数据资源&#xff0c;那么一定就需要采用认证检测机制&#xff0c;于是SpringCloud进行认证处理&#xff0c;就可以使用SpringSecurity 来实现了&#xff0c;但是如果你真的去使用了SpringSe…

当你左右看看没有发现我时,千万千万别往看……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。周五&#xff0c;又是一个考试的周五&#xff0c;因为本周都在做项目&#xff0c;还以为同学们没有好好的备考&#xff0c;估计考的不好&#xff0c;没想到今天测试的结果是自从考试以来最…

2018/7/11-纪中某C组题【jzoj1293,jzoj1294,jzoj1295】

前言 今天C组题目有毒&#xff0c;第一题题目玄学&#xff0c;第二题就是不会&#xff0c;第三题考的贼偏。fw(hjw&#xff0c;his博客&#xff1a;https://blog.csdn.net/gx_man_vip)说今天B组题目还行早知道就去做B组了qwq 今日分数 去掉了十分强大的纪中dalao 正题 T1&…

关系型数据库的分片原则

来自Citus的Ozgun Erdogan分享了进行数据库分片的三个原则&#xff0c;并强调应用类型是决定数据库分片最主要的因素。其中B2B类型的应用最容易进行数据库分片。 在数据库很小的时候&#xff0c;可以很容易地通过添加硬件来扩展数据库。但随着数据表数量的不断增长&#xff0c…

分布式架构--基本思想汇总

转载自 分布式架构&#xff0d;&#xff0d;基本思想汇总 在互联网大行其道的今天&#xff0c;各种分布式系统已经司空见惯。搜索引擎、电商网站、微博、微信、O2O平台。。凡是涉及到大规模用户、高并发访问的&#xff0c;无一不是分布式。 关于分布式系统&#xff0c;并没有…

花了100多去KTV不是唱歌,竟然是……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。老师&#xff0c;歌词可以实现&#xff0c;不过比较麻烦~也还行你这样 准备几首歌的歌词就行到时候只演示这几首歌如果是其他的哥的话&#xff0c;就显示暂无歌词行&#xff0c;有时间就试…

jzoj4272-序章-弗兰德的秘密【树形dp】

正题 大意 两棵树&#xff0c;它们的相似值是它们留下最多的节点使它们的结构相同。求相似值。 这两颗树就是结构相同的&#xff0c;相似值是8。 解题思路 就是树形dp。可以用f[i][j]f[i][j]表示树1的第ii号节点和它的子树与树2的j" role="presentation" s…

从NIO到Netty开发

转载自 从NIO到Netty开发 1. 从传统BIO到NIO的升级 Client/Server模型是网络编程的基本模型&#xff0c;服务端提供位置信息&#xff0c;客户端通过连接操作向服务端发起连接请求&#xff0c;通过三次握手建立连接&#xff0c;如果连接建立成功&#xff0c;双方就可以通过网…

Orleans入门例子

Orleans是微软开源的分布式actor模型框架.actor模型的原理网络上有很多文章.有许多理论性的文章,深刻地我都不知道怎么应用.在这里我就不赘述了.既然是博客,就说说自己的理解。 对于编程来说&#xff0c;不管是前台还是后台&#xff0c;在现在的计算机环境下&#xff0c;多线程…

JavaScript常用单词整理总结

第一章object对象undefined未定义变量boolean布尔类型sort()对数组排序charAt返回在指定位置的字符toLowerCase()把字符串转换为小写button按钮break结束循环toUpperCase()把字符串转换为大写split(str)将字符串分割为字符串数组length获取数组的长度continue结束当前循环&…

JWT 应用

文章目录JWT工具模块Token认证微服务JWT授权监测网关认证过滤消费端获取JWTJWT工具模块 如果要想在项目之中去使用JWT技术&#xff0c;那么就必须结合到已有的模块之中,最佳的做法就是将JWT的相关的处理 操作做为一个自动的starter组件进行接入 1、【microcloud项目】既然要开…

淘宝秒杀系统设计的几个注意点

转载自 淘宝秒杀系统设计的几个注意点 还记得2013年的小米秒杀吗&#xff1f;三款小米手机各11万台开卖&#xff0c;走的都是大秒系统&#xff0c;3分钟后成为双十一第一家也是最快破亿的旗舰店。经过日志统计&#xff0c;前端系统双11峰值有效请求约60w以上的QPS &#xff0…

.NET Core 2.0 开源Office组件 NPOI

前言 去年 12 月&#xff0c;我移植了大家所熟知 NPOI 到 .NET Core 版本&#xff0c;这里是当时发的博客&#xff0c;当时得到了很多同学的支持&#xff0c;社区反应也很好&#xff0c;在这里非常感谢当时推荐的朋友们。 去年的那个版本是针对于 .NET Core 1.0 的&#xff0…

老师们一直在……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。【随便写写】为了了解同学们在公司的情况&#xff0c;和佟老师上了的做了个在线问卷调查&#xff0c;把一些常见的问题设置在调查中&#xff0c;根据调查数据&#xff0c;然后挨个的去解决…