EF Core 的
Set<t>()</t>方法是获取数据库表对应
DbSet<t></t>实例的核心方式,它不依赖 DbContext 中是否已声明属性,适合动态、泛型或运行时类型不确定的场景。配合表达式树(
Expression)和
IQueryable,就能实现真正的动态查询。
Set() 基础用法:按需获取 DbSet
当你没有在 DbContext 类里显式定义
public DbSet<product> Products { get; set; }</product>,或者类型 T 是运行时才知道的(比如从字符串解析),就靠 context.Set<t>()</t>: 直接调用:
var products = context.Set<product>();</product>等价于访问
context.Products泛型封装更灵活:
public IQueryable<t> GetTable<t>() where T : class => context.Set<t>();</t></t></t>注意:返回的是未执行的
IQueryable<t></t>,只有调用
ToList()、
FirstOrDefault()等才会真正发 SQL
用 Set + Expression 构建动态 Where 条件
避免写一堆 if-else 判断参数是否为空,把筛选逻辑交给表达式树组装:
先反射拿到请求参数对象的属性值(如search.Name、
search.Status) 再根据实体类映射关系,找到对应数据库字段(如
Product.Name→
ProductName) 用
Expression.Parameter、
Expression.Property、
Expression.Equal等拼出条件表达式 最后用
queryable.Where(expression)应用,EF Core 会自动翻译成 SQL WHERE 子句
例如:用户只输入了 “类别 ID=5”,就只生成
WHERE CategoryId = 5;如果还填了名称,就追加
AND Name LIKE '%xxx%'—— 全部在表达式层完成,不硬编码。
配合 FromSqlRaw 或 ExecuteUpdate 实现更动态操作
Set<t>()</t>返回的
DbSet<t></t>还支持原生 SQL 和批量更新,进一步扩展动态能力:
context.Set<order>().FromSqlRaw("SELECT * FROM Orders WHERE Status = {0}", status)</order> —— 动态拼接 SQL 查询(务必用参数化防止注入)
context.Set<product>().Where(x => x.CategoryId == 5).ExecuteUpdate(x => x.SetProperty(p => p.Price, p => p.Price * 1.1m))</product>—— 不查数据,直接数据库内批量涨价 甚至可结合配置文件或前端传来的 JSON 规则,驱动字段名、操作符、值来源,实现低代码查询引擎
注意事项和常见坑
用
Set<t>()</t>动态查询虽灵活,但几个关键点容易忽略: 类型必须注册到 DbContext:即使没声明 DbSet 属性,也要在
OnModelCreating或
ModelBuilder中通过
modelBuilder.Entity<t>()</t>显式配置,否则
Set<t>()</t>会报错 导航属性加载需手动处理:用
Set<t>()</t>查询后,
.Include()仍有效,但别忘了链式调用,比如
context.Set<blog>().Include(b => b.Posts)</blog>跟踪与非跟踪要分清:默认开启变更跟踪,若只是读取报表类数据,加
.AsNoTracking()可显著提升性能 避免在循环中反复调用 Set
基本上就这些。Set 方法本身很简单,难点在于怎么把它和表达式、配置、业务规则串起来——核心不是“能不能做”,而是“怎么组织得干净又可控”。
