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

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

以下是一些适用场景:

  • 多租户: 在多租户应用程序中,每个租户的数据应该彼此隔离。通过使用全局查询筛选器,可以轻松确保每次查询仅返回特定租户的数据,而无需在每个查询中显式添加Where子句。

  • **软删除:**软删除是一种数据管理策略,允许在数据库中保留已删除的数据,而不是完全从数据库中移除。通过使用全局查询筛选器,可以自动排除那些被标记为已删除的数据行,从而在查询结果中只包含未删除的数据。

  • 数据访问权限 :在某些应用中,您可能基于用户的角色或权限来限制他们可以访问的数据。全局查询筛选器可以确保即使忘记了添加权限检查,查询也仍然只返回用户可以访问的数据。


软删除

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

以下是一个示例

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

cs 复制代码
public class MyEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsDeleted { get; set; }
}
  1. 配置筛选器:接下来,在OnModelCreating方法中使用HasQueryFilter API为实体类型配置查询筛选器。这些筛选器以LINQ查询谓词的形式存在,并自动应用于所有相关的查询操作。
cs 复制代码
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyEntity>()
        .HasQueryFilter(e => !e.IsDeleted);
}
  1. 执行删除操作:当你需要删除一个实体时,只需将IsDeleted属性设置为true,而不是实际从数据库中删除它。
cs 复制代码
var entity = new MyEntity { Id = 1, Name = "Example" };
context.MyEntities.Add(entity);
await context.SaveChangesAsync();

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

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

cs 复制代码
entity.IsDeleted = false;
await context.SaveChangesAsync();

优缺点:

  • 优点

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

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

多租户

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

以下是一个示例

  1. 定义实体:首先,你需要定义包含特定属性的实体类,例如用于标识租户的TenantId属性。、
cs 复制代码
public class MyEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int TenantId { get; set; }
}
  1. 配置筛选器:接下来,在OnModelCreating方法中使用HasQueryFilter API为实体类型配置查询筛选器。这些筛选器以LINQ查询谓词的形式存在,并自动应用于所有相关的查询操作。
cs 复制代码
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyEntity>()
        .HasQueryFilter(e => e.TenantId == _currentTenantId);
}
  1. 执行查询操作:当你需要查询数据时,只需根据当前租户的ID进行过滤即可。
cs 复制代码
// 假设当前租户的ID为1
var entities = context.MyEntities.ToList();
  1. 添加新记录:当你需要添加一个新记录时,只需设置TenantId属性为当前租户的ID即可。
cs 复制代码
var entity = new MyEntity { Name = "Example" };
entity.TenantId = _currentTenantId;
context.MyEntities.Add(entity);
await context.SaveChangesAsync();

优缺点:

  • 优点

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

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

数据访问权限

下面是一个示例:

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

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

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

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

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

cs 复制代码
var adminUsers = context.Users.ToList();

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

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


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

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

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

cs 复制代码
var allStudents = context.Students.IgnoreQueryFilters().ToList();

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

相关推荐
疯一样的码农14 分钟前
Apache Maven简介
java·maven·apache
聊无生18 分钟前
JavaSrcipt 函数高级
开发语言·前端·javascript
小安同学iter26 分钟前
Java进阶五 -IO流
java·开发语言·intellij-idea
Hello World and You27 分钟前
R ggplot2 绘图细节 geom_text展示不全 y轴坐标细节 x轴标题
开发语言·r语言
sukalot31 分钟前
windows C#-异步文件访问
开发语言·c#
码到成功>_<36 分钟前
Spring Boot实现License生成和校验
数据库·spring boot·后端
尽兴-37 分钟前
Redis模拟延时队列 实现日程提醒
java·redis·java-rocketmq·mq
熬夜学编程的小王1 小时前
【C++篇】从基础到进阶:全面掌握C++ List容器的使用
开发语言·c++·list·双向链表·迭代器失效
悄悄敲敲敲1 小时前
C++:智能指针
开发语言·c++
书埋不住我1 小时前
java第三章
java·开发语言·servlet