您如何在实体框架的数据库级别执行复杂的“或”过滤器?
Posted
技术标签:
【中文标题】您如何在实体框架的数据库级别执行复杂的“或”过滤器?【英文标题】:How do you do complex "OR" filters at the database level in Entity Framework? 【发布时间】:2022-01-15 12:52:46 【问题描述】:执行以下 SQL 查询:
select * from model where (Foo = 'a' and Bar = 'b') or (Foo = 'b' and Bar = 'b')
如果您不知道应用的过滤器数量,您如何将其转换为在数据库级别工作的实体框架表达式?
我制作了以下程序来演示我在说什么以及我已经尝试过什么。如果不首先从数据库中取回所有内容而不使用表达式树,我就无法找到一种应用过滤器的方法,这似乎有点矫枉过正。
using Microsoft.EntityFrameworkCore;
var contextOptions = new DbContextOptionsBuilder<TestContext>()
.UseInMemoryDatabase("testdb")
.Options;
using (var context = new TestContext(contextOptions))
context.Database.EnsureCreated();
var models = new Model[]
new Model
Foo = "a",
Bar = "a"
,
new Model
Foo = "a",
Bar = "b"
,
new Model
Foo = "b",
Bar = "a"
,
new Model
Foo = "b",
Bar = "b"
,
;
await context.AddRangeAsync(models);
await context.SaveChangesAsync();
var filters = new Filter[]
new Filter
Foo = "a",
Bar = "b"
,
new Filter
Foo = "b",
Bar = "b"
;
Console.WriteLine("Complex object:");
try
var objectFilteredModels = await context.Models
.Where(m => filters.Any(f => f.Foo == m.Foo && f.Bar == m.Bar))
.ToListAsync();
catch (InvalidOperationException ex)
Console.WriteLine(ex.Message);
Console.WriteLine("\nDictionary:");
var filterDictionary = filters.ToDictionary(f => f.Foo, f => f.Bar);
try
var dictionaryFilteredModels = await context.Models
.Where(m => filterDictionary.Keys.Any(k => k == m.Foo && filterDictionary[k] == m.Bar))
.ToListAsync();
catch (InvalidOperationException ex)
Console.WriteLine(ex.Message);
Console.WriteLine("\nSeparate arrays:");
var foos = filters.Select(f => f.Foo).ToList();
var bars = filters.Select(f => f.Bar).ToList();
try
var arraysFilteredModels = await context.Models
.Where(m => foos.Any(f => f == m.Foo && bars.ElementAt(foos.IndexOf(f)) == m.Bar))
.ToListAsync();
catch (InvalidOperationException ex)
Console.WriteLine(ex.Message);
Console.WriteLine("\nNon-DB query:");
var allModels = await context.Models.ToListAsync();
var filteredModels = allModels.Where(m => filters.Any(f => f.Foo == m.Foo && f.Bar == m.Bar)).ToList();
Console.WriteLine($"no error, filtered model count: filteredModels.Count");
public class TestContext : DbContext
public TestContext()
public TestContext(DbContextOptions<TestContext> options)
: base(options)
public DbSet<Model> Models => Set<Model>();
public class Model
public int Id get; set;
public string Foo get; set; = null!;
public string? Bar get; set;
public class Filter
public string Foo get; set; = null!;
public string? Bar get; set;
【问题讨论】:
您将需要使用类似LINQKit 的东西来构建Expression
树或类似Dynamic LINQ 的东西来将filters
数组的字符串表示形式转换为Expresson
树。真的没有办法解决它。我会推荐 LINQKit 或滚动您自己的简化版本。
***.com/q/14621450/861716
【参考方案1】:
直译
select * from model where (Foo = 'a' and Bar = 'b') or (Foo = 'b' and Bar = 'b')
是
from m in db.Models
where (m.Foo == 'a' && m.Bar == 'b') || (m.Foo == 'b' && m.Bar == 'b')
select m
【讨论】:
是的,但是如果您不知道filters
对象的内容/长度怎么办?我将编辑我的问题以使其更清楚。以上是关于您如何在实体框架的数据库级别执行复杂的“或”过滤器?的主要内容,如果未能解决你的问题,请参考以下文章