当前位置: 首页 > news >正文

全局查询筛选器适用场景 以及各场景示例

EF Core中的全局查询筛选器(Global Query Filters)是一种强大的功能,可以在实体框架的DbContext级别为特定的EntityType设置默认的过滤条件。这些筛选器自动应用于所有涉及到相关实体的LINQ查询中,无论是直接查询还是通过Include或导航属性间接引用的情况。

以下是一些适用场景:

  • 多租户:在多租户应用程序中,每个租户的数据应该彼此隔离。通过使用全局查询筛选器,可以轻松确保每次查询仅返回特定租户的数据,而无需在每个查询中显式添加Where子句。
  • 软删除:软删除是一种数据管理策略,允许在数据库中保留已删除的数据,而不是完全从数据库中移除。通过使用全局查询筛选器,可以自动排除那些被标记为已删除的数据行,从而在查询结果中只包含未删除的数据。
  • 数据访问权限:在某些应用中,您可能基于用户的角色或权限来限制他们可以访问的数据。全局查询筛选器可以确保即使忘记了添加权限检查,查询也仍然只返回用户可以访问的数据。

软删除

软删除是一种数据管理策略,它允许在数据库中保留已删除的数据,而不是完全从数据库中移除。这种策略通常通过添加一个布尔类型的列(如IsDeleted)来实现,该列标记着每行数据是否已被逻辑删除。

以下是一个示例

1.定义实体:首先,你需要定义包含特定属性的实体类,例如用于软删除的IsDeleted属性。

public class MyEntity
{public int Id { get; set; }public string Name { get; set; }public bool IsDeleted { get; set; }
}

2. 配置筛选器:接下来,在OnModelCreating方法中使用HasQueryFilter API为实体类型配置查询筛选器。这些筛选器以LINQ查询谓词的形式存在,并自动应用于所有相关的查询操作。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.Entity<MyEntity>().HasQueryFilter(e => !e.IsDeleted);
}


3. 执行删除操作:当你需要删除一个实体时,只需将IsDeleted属性设置为true,而不是实际从数据库中删除它。

var entity = new MyEntity { Id = 1, Name = "Example" };
context.MyEntities.Add(entity);
await context.SaveChangesAsync();entity.IsDeleted = true;
await context.SaveChangesAsync();

4.恢复删除的数据:如果你意外删除了数据,你可以轻易地通过更改IsDeleted标志来恢复。

entity.IsDeleted = false;
await context.SaveChangesAsync();

优缺点: 

  • 优点

    • 恢复数据:如果你意外删除了数据,你可以轻易地通过更改IsDeleted标志来恢复。
    • 审计和历史记录:保留了数据的历史记录,有助于进行审计和分析。
    • 提高性能:在某些情况下,软删除可以提高性能,因为它避免了实际的数据库删除操作。
  • 缺点

    • 维护开销:需要定期清理未使用的数据,否则可能会占用过多的存储空间。
    • 查询复杂性:每个查询都需要包含IsDeleted条件,除非确实需要访问已删除的数据。

多租户

多租户架构是一种将多个租户(用户或组织)共享同一套应用程序或系统的方式,同时保持每个租户的数据隔离性。这种架构模式在许多现代应用程序中被广泛使用,例如云服务提供商、SaaS应用程序等。

以下是一个示例

1. 定义实体:首先,你需要定义包含特定属性的实体类,例如用于标识租户的TenantId属性。、

public class MyEntity
{public int Id { get; set; }public string Name { get; set; }public int TenantId { get; set; }
}

2. 配置筛选器:接下来,在OnModelCreating方法中使用HasQueryFilter API为实体类型配置查询筛选器。这些筛选器以LINQ查询谓词的形式存在,并自动应用于所有相关的查询操作。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.Entity<MyEntity>().HasQueryFilter(e => e.TenantId == _currentTenantId);
}

3. 执行查询操作:当你需要查询数据时,只需根据当前租户的ID进行过滤即可。

// 假设当前租户的ID为1
var entities = context.MyEntities.ToList();

4. 添加新记录:当你需要添加一个新记录时,只需设置TenantId属性为当前租户的ID即可。

var entity = new MyEntity { Name = "Example" };
entity.TenantId = _currentTenantId;
context.MyEntities.Add(entity);
await context.SaveChangesAsync();

 优缺点:

  • 优点

    • 可定制性和灵活性:每个租户可以根据需要定制自己的数据视图和功能。
    • 简化维护:可以在一个集中的位置更新和维护应用程序。
  • 缺点

    • 数据隔离:需要小心设计以防止数据泄露或混肴。
    • 性能挑战:如果所有租户都在同一时间活跃,可能会对性能造成压力。
    • 备份和恢复:可能需要更复杂的备份和恢复策略来满足不同租户的需求。

数据访问权限

 下面是一个示例:

假设我们有一个名为User的实体类,其中包含一个名为Role的角色字段,表示用户的角色。我们希望在执行查询时自动过滤掉不属于特定角色的用户。

首先,我们需要在DbContext的OnModelCreating方法中为User实体类型配置全局查询筛选器。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.Entity<User>().HasQueryFilter(u => u.Role == "Admin");
}

上述代码将自动应用一个筛选条件,只返回角色为"Admin"的用户记录。

接下来,我们可以执行普通的LINQ查询来获取所有管理员用户。

var adminUsers = context.Users.ToList();

由于已经配置了全局查询筛选器,上述查询将自动过滤掉非管理员用户,并返回所有管理员用户列表。

全局查询筛选器仅适用于直接查询和通过导航属性引用的情况。如果需要对关联表进行数据访问权限的查询,可以在关联表中也使用类似的全局查询筛选器。还可以根据需要自定义全局查询筛选器的表达式,以满足更复杂的业务需求。


忽略全局查询过滤器(IgnoreQueryFilters()

如果你想在执行针对Student实体类型的查询时忽略全局查询过滤器,可以使用IgnoreQueryFilters()方法。

例如,以下代码将忽略全局查询过滤器并返回所有Student记录:

var allStudents = context.Students.IgnoreQueryFilters().ToList();

通过调用IgnoreQueryFilters()方法,你可以暂时禁用全局查询过滤器,以便执行不受其影响的查询。

相关文章:

  • 算法刷题day54:搜索(一)
  • Alamofire常见GET/POST等请求方式的使用,响应直接为json
  • HQL面试题练习 —— 取出累计值与1000差值最小的记录
  • 链表经典题目—相交链表和链表倒数第k个节点
  • 基于香橙派 Ai Pro的ROS Qt人机交互软件部署指南
  • 漫步者x1穷鬼耳机双耳断连
  • idea配置ssh、sftp连接服务器,docker插件使用,极其方便,无需再开第三方软件去操作服务器了,集成用于Idea一体
  • 【Java继承】(超级详细!!!)
  • 【pm2 - sdk 集成到程序中,典型用法】
  • 堆结构知识点复习——玩转堆结构
  • 当HR问你是否单身时,该怎么回答?
  • 高德地图之获取经纬度并且根据获取经纬度渲染到路线规划
  • Upstream最新发布2024年汽车网络安全报告-百度网盘下载
  • Unity 生成物体的几种方式
  • C数据结构:二叉树
  • [译] 怎样写一个基础的编译器
  • 《剑指offer》分解让复杂问题更简单
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 4. 路由到控制器 - Laravel从零开始教程
  • avalon2.2的VM生成过程
  • es6(二):字符串的扩展
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • spring boot 整合mybatis 无法输出sql的问题
  • 彻底搞懂浏览器Event-loop
  • 搭建gitbook 和 访问权限认证
  • 工程优化暨babel升级小记
  • 解析 Webpack中import、require、按需加载的执行过程
  • 那些年我们用过的显示性能指标
  • 让你的分享飞起来——极光推出社会化分享组件
  • 携程小程序初体验
  • 一些关于Rust在2019年的思考
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • #14vue3生成表单并跳转到外部地址的方式
  • #Linux(权限管理)
  • #NOIP 2014#Day.2 T3 解方程
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (2.2w字)前端单元测试之Jest详解篇
  • (3)选择元素——(17)练习(Exercises)
  • (C语言)逆序输出字符串
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (十)T检验-第一部分
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (学习日记)2024.01.09
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • ../depcomp: line 571: exec: g++: not found
  • .htaccess配置重写url引擎
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .net mvc 获取url中controller和action
  • .NET 设计一套高性能的弱事件机制
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .net2005怎么读string形的xml,不是xml文件。