gpt4 book ai didi

c# - 在 SQL Server 上筛选 Entity Framework 结果

转载 作者:太空宇宙 更新时间:2023-11-03 14:07:30 24 4
gpt4 key购买 nike

首先:我们做 TPH(每个层次结构的表),这会使事情变得简单得多。

我有大约 20 个 POCO,它们在某些情况下都具有相似的属性。我关心的类似属性是 ___.CreatedDate___.UpdatedDate .对于某些 POCO,UpdatedDate没有意义,所以他们没有那个属性(property)。 CreatedDate将永远存在,UpdatedDate可能为空。有时还有第三个字段。

无论我查询的是 20 个 POCO 中的哪一个,从数据库中检索对象的查询看起来总是一样的。但是,该查询被重复了 20 次,每个对象对应一种类型。我能够将检索部分分解为扩展方法(关闭 IDbSet<T> )以进行初始查找和连接,将日期范围过滤留给消费者作为练习。我现在想将 20 个看起来几乎相同的日期范围过滤器合并为一个,但遇到了查询理解方面的问题。

根据 POCO,日期过滤逻辑是应该检查 UpdatedDate 并将其值与阈值进行比较。如果 UpdatedDate 为 null(或属性不存在),则应改用 CreatedDate。

我首先在每个 POCO 上创建一个静态属性 getter,我将其命名为“DateFields”。它的类型为 IEnumerable<Expression<Func<T, DateTime?>>>看起来像这样:

get
{
yield return x => x.UpdatedDate;
yield return x => x.CreatedDate;
yield return x => x.Date;
}

这些字段按照我希望它们被检查的顺序返回,并且对于每个 POCO 都是唯一的。

然后我创建了一个谓词来根据高低范围检查每个值:

public static bool DatesBetween<T> (T value, IEnumerable<Expression<Func<T, DateTime?>>> dates, DateTime? dateFrom, DateTime? dateTo)
{
var firstDate = dates
.Select(expression => expression.Compile())
.FirstOrDefault(func => func(value) != null);

if (firstDate == null)
return false;

var minDate = dateFrom.GetValueOrDefault(SqlDateTime.MinValue.Value);
var maxDate = dateTo.GetValueOrDefault(SqlDateTime.MaxValue.Value);

var actualDate = firstDate(value);

return (minDate <= actualDate && actualDate <= maxDate);
}

然而,正如预期的那样,当我尝试在我的 IQueryable 中使用它时,我得到一个运行时异常,因为在 SQL 中没有对 DatesBetween 的转换。我希望通过保留表达式树,我可以……我不知道……让 EF 开心。整个事情是这样使用的:

return Entities
.GetEntitiesBySomeField(field := "magic value")
.Where(entity => RepositoryExtensions.DatesBetween(entity, MyPOCO.MyDates, dateFrom, dateTo));

我问的很清楚,有没有一种方法可以在不执行 AsEnumerable () 的情况下完成这种通用过滤(它确实有效,但没有实现我在 DB 上过滤的目标)。

最佳答案

我最近在一个项目中做了类似的事情。我最终做的是实现存储库模式并在存储库上创建一个名为“ApplyFilter”的方法,它看起来像:

void ApplyFilter(Expression<Func<TEntity, bool>> predicate)
{
if(this.resultSet == null)
{
this.resultSet = this.context.Set<TEntity>().AsQueryable();
}

this.resultSet = this.resultSet.Where(predicate);
}

我的存储库中有一个名为“ResultSet”的属性,它刚刚返回 IQueryable resultSet 字段并强制枚举结果(触发 EF 的数据库调用)。这样我就可以在枚举结果之前明确地应用所有动态创建的表达式。

我的代码与您的代码之间的真正区别在于,我的代码将 bool 谓词附加到最终表达式树,而当您尝试在最终表达式树中使用您的谓词时。我的方式基本上是为 SQL 创建/附加 WHERE 子句,您的方式尝试从“DatesBetween”方法生成 SQL 函数调用。

这里有一些尝试:

    public static Expression<Func<TEntity, bool>> MakeDateRange<TEntity>(DateTime? dateFrom, DateTime? dateTo)
{
var et = typeof(TEntity);
var param = Expression.Parameter(et, "a");
var prop = et.GetProperty("UpdatedDate");
Expression body = null, left = null, right = null;
if (prop == null)
{
prop = et.GetProperty("CreatedDate");
if (prop == null)
{
prop = et.GetProperty("Date");
}
}

if (dateFrom.HasValue)
{
left = Expression.GreaterThanOrEqual(Expression.PropertyOrField(param, prop.Name), Expression.Constant(dateFrom.GetValueOrDefault()));
}

if (dateTo.HasValue)
{
right = Expression.LessThanOrEqual(Expression.PropertyOrField(param, prop.Name), Expression.Constant(dateTo.GetValueOrDefault()));
}

if (left != null && right != null)
{
body = Expression.AndAlso(left, right);
}
else if (left != null)
{
body = left;
}
else
{
body = right;
}

return Expression.Lambda<Func<TEntity, bool>>(body, param);
}

关于c# - 在 SQL Server 上筛选 Entity Framework 结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8933939/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com