Entity Framework Core中的全局查询过滤器实现与应用

发布:2024-09-14 11:40 阅读:15 点赞:0

全局查询过滤器(Global Query Filter)是Entity Framework Core中一个非常实用的功能。它允许我们在模型层级定义过滤条件,这些条件会自动应用于所有针对指定类型的查询。简单来说,Entity Framework会在执行LINQ查询之前,自动将过滤条件添加到WHERE子句中。通常,全局查询过滤器在上下文的OnModelCreating方法中应用。这些过滤器也会自动应用于涉及到的实体类型,包括作为导航属性的间接引用类型。

一. 全局查询过滤器的常见用途

  1. 软删除:在实体类型中定义一个IsDeleted属性,当数据被标记为删除时,应用程序不需要显示这些数据。
  2. 多租户:在实体类型中定义一个TenantId属性,以支持多租户的数据隔离。

二. 示例

2.1 创建Employee表

首先,我们创建一个Employee表,该表包含一个IsDeleted列,用于标记记录是否被删除。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Employee](
    [Id] [intNOT NULL,  -- 员工ID,主键
      NULL,  -- 员工姓名
    [IsDeleted] [bitNULL,  -- 是否删除标志
 CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED
(
    [IdASC
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]
ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO

-- 插入数据
INSERT [dbo].[Employee] ([Id], [Name], [IsDeleted]) VALUES (1, N'Jignesh'0)
INSERT [dbo].[Employee] ([Id], [Name], [IsDeleted]) VALUES (2, N'Rakesh'0)
INSERT [dbo].[Employee] ([Id], [Name], [IsDeleted]) VALUES (3, N'Tejas'0)
INSERT [dbo].[Employee] ([Id], [Name], [IsDeleted]) VALUES (4, N'Rajesh'1)

2.2 定义实体和上下文类

Employee.cs

using System.ComponentModel.DataAnnotations;  // 引入数据注解
using System.ComponentModel.DataAnnotations.Schema;  // 引入数据注解的表和列映射

namespace GlobalFilterExample.Model
{
    [Table("Employee")]  // 映射到数据库中的Employee表
    public class Employee
    {
        [Key]  // 指定Id为主键
        public int Id { getset; }  // 员工ID

        public string Name { getset; }  // 员工姓名

        public bool IsDeleted { getset; }  // 是否删除标志
    }
}

EntityModelContext.cs

using Microsoft.EntityFrameworkCore;  // 引入Entity Framework Core
using System;

namespace GlobalFilterExample.Model
{
    public class EntityModelContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            // 配置数据库连接字符串
            optionsBuilder.UseSqlServer(@"Server=(local);Database=Test;user Id=sa; password=Passwd@12;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 应用全局查询过滤器
            modelBuilder.Entity()
                .HasQueryFilter(p => !p.IsDeleted);  // 过滤掉已删除的记录

            base.OnModelCreating(modelBuilder);  // 调用基类方法
        }

        public DbSet Employees { getset; }  // DbSet属性,表示Employee表
    }
}

2.3 示例代码

using (EntityModelContext context = new EntityModelContext())
{
    Console.WriteLine("---------------With Global Query Filters---------------");
    
    // 获取所有未删除的员工
    var data = context.Employees.ToList();
    
    foreach (var d in data)
    {
        Console.WriteLine("{0}\t{1}", d.Id, d.Name);  // 输出员工ID和姓名
    }
    Console.ReadLine();
}

2.4 输出结果

---------------With Global Query Filters---------------
1   Jignesh
2   Rakesh
3   Tejas

三. 禁用全局过滤器

全局查询过滤器会应用于所有LINQ查询。在某些情况下,我们可能不需要这些过滤器。可以使用IgnoreQueryFilters()方法禁用全局过滤器。

3.1 示例代码

using (EntityModelContext context = new EntityModelContext())
{
    // 忽略全局查询过滤器,获取所有员工,包括已删除的记录
    var data1 = context.Employees
        .IgnoreQueryFilters().ToList();
    
    foreach (var d in data1)
    {
        Console.WriteLine("{0}\t{1}", d.Id, d.Name);  // 输出员工ID和姓名
    }
}

3.2 输出结果

1   Jignesh
2   Rakesh
3   Tejas
4   Rajesh

四. 限制

全局查询过滤器有以下限制:

  1. 不能包含导航属性:过滤器不能引用导航属性。
  2. 只能在继承层次结构的根实体类型上定义:它只能在继承层次结构的根实体类型上定义。
  3. IgnoreQueryFilters方法会忽略所有过滤器:不能单独移除特定的过滤器。

五. 总结

全局查询过滤器(或模型级查询过滤器)是Entity Framework Core中一个非常有用的功能。它帮助开发者在模型层级上应用过滤条件,防止在开发过程中遗漏某些数据过滤逻辑。这种机制可以确保应用程序始终只处理有效的数据,从而提高了数据的安全性和一致性。