gpt4 book ai didi

c# - 如何将表达式传递到 Entity Framework LINQ 查询 OrderBy 子句中

转载 作者:行者123 更新时间:2023-11-30 21:31:12 26 4
gpt4 key购买 nike

我有以下 LINQ 查询:

using (var context = new EUContext())
{
var tmp = context.Terms.Include(x => x.StudentCourses)
.Where(x => x.StudentID == studentId && x.DepartmentID == departmentId)
.OrderBy(x => x.AcademicYear)
.ThenBy(x=> x.TermRegistered == "Fall" ? 1 :
x.TermRegistered == "Spring" ? 2 : 3));

return tmp.ToList();
}

我正在尝试移动 ThenBy 子句中的 OrdyBy 以清理代码。我正在尝试使用如下表达式:

private static Expression<Func<string, int>> TermsOrder(string x)
{
return (x == "Fall" ? 1 :
x == "Spring" ? 2 : 3);
}

我的代码应该是这样的:

using (var context = new EUContext())
{
var tmp = context.Terms.Include(x => x.StudentCourses)
.Where(x => x.StudentID == studentId && x.DepartmentID == departmentId)
.OrderBy(x => x.AcademicYear)
.ThenBy(x=> TermsOrder(x.TermRegistered));

return tmp.ToList();
}

不幸的是,该表达式不起作用,表达式正文中有一条长长的波浪线,并显示以下错误消息:

Cannot implicitly convert type 'int' to 'System.Linq.Expressions.Expression>

我做错了什么?这是我第一次尝试使用表达式,我知道由于没有完全理解表达式的工作原理,我遗漏了一些明显的东西。

谢谢

最佳答案

这并不像看起来那么简单。您需要组合 Expression 或构建 Expression 来生成您想要的内容,不幸的是,C# 在这方面没有提供很多帮助。

最简单的方法是使用 LambdaExpression 组合的扩展方法。它依赖于一些 Expression 扩展方法,用于在 Expression 中将一个 Expression 替换为另一个:

public static class ExpressionExt {
// Compose: f.Compose(g) => x => f(g(x))
/// <summary>
/// Composes two LambdaExpression into a new LambdaExpression: f.Compose(g) => x => f(g(x))
/// </summary>
/// <param name="fFn">The outer LambdaExpression.</param>
/// <param name="gFn">The inner LambdaExpression.</param>
/// <returns>LambdaExpression representing outer composed with inner</returns>
public static Expression<Func<T, TResult>> Compose<T, TIntermediate, TResult>(this Expression<Func<TIntermediate, TResult>> fFn, Expression<Func<T, TIntermediate>> gFn) =>
Expression.Lambda<Func<T, TResult>>(fFn.Body.Replace(fFn.Parameters[0], gFn.Body), gFn.Parameters[0]);

/// <summary>
/// Replaces a sub-Expression with another Expression inside an Expression
/// </summary>
/// <param name="orig">The original Expression.</param>
/// <param name="from">The from Expression.</param>
/// <param name="to">The to Expression.</param>
/// <returns>Expression with all occurrences of from replaced with to</returns>
public static Expression Replace(this Expression orig, Expression from, Expression to) => new ReplaceVisitor(from, to).Visit(orig);
}

/// <summary>
/// Standard ExpressionVisitor to replace an Expression with another in an Expression.
/// </summary>
public class ReplaceVisitor : ExpressionVisitor {
readonly Expression from;
readonly Expression to;

public ReplaceVisitor(Expression from, Expression to) {
this.from = from;
this.to = to;
}

public override Expression Visit(Expression node) => node == from ? to : base.Visit(node);
}

现在您可以创建您的方法,该方法采用代表您要测试的字段的 lambda。它使用本地 LambdaExpression 作为最终结果的模板:

public static class Util {
static Expression<Func<string, int>> TermOrderTemplateFn = p => (p == "Fall" ? 1 : p == "Spring" ? 2 : 3);
public static Expression<Func<TRec, int>> TermsOrder<TRec>(Expression<Func<TRec, string>> selectorFn) =>
TermOrderTemplateFn.Compose(selectorFn);
}

现在您可以在表达式中调用该方法,传入一个代表所需字段(或字段表达式)的 lambda 以进行测试:

var tmp = context.Terms.Include(x => x.StudentCourses).AsQueryable()
.Where(x => x.StudentID == studentId && x.DepartmentID == departmentId)
.OrderBy(x => x.AcademicYear)
.ThenBy(Util.TermsOrder<Term>(p => p.TermRegistered));

注意:我正在调用 context.Terms.First() Term 的类型,但您需要使用实际的正确类型TermsOrder 调用中的名称。您也可以改为执行 TermsOrder((Term p) => ...)

我可能更愿意创建一个特殊版本的 ThenBy 以便您可以使用类型推断来确定记录类型:

public static class EFExt {
static Expression<Func<string, int>> TermThenOrderTemplateFn = p => (p == "Fall" ? 1 : p == "Spring" ? 2 : 3);
public static IOrderedQueryable<T> ThenByTerm<T>(this IOrderedQueryable<T> src, Expression<Func<T, string>> selectorFn) =>
src.ThenBy(TermThenOrderTemplateFn.Compose(selectorFn));
}

然后就可以直接使用了:

var tmp = context.Terms.Include(x => x.StudentCourses).AsQueryable()
.Where(x => x.StudentID == studentId && x.DepartmentID == departmentId)
.OrderBy(x => x.AcademicYear)
.ThenByTerm(p => p.TermRegistered);

关于c# - 如何将表达式传递到 Entity Framework LINQ 查询 OrderBy 子句中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53509725/

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