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

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()方法,你可以暂时禁用全局查询过滤器,以便执行不受其影响的查询。

  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值