Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在实体框架的另一个C#表达式中使用一个C#表达式?_C#_Entity Framework_Linq_Expression Trees - Fatal编程技术网

如何在实体框架的另一个C#表达式中使用一个C#表达式?

如何在实体框架的另一个C#表达式中使用一个C#表达式?,c#,entity-framework,linq,expression-trees,C#,Entity Framework,Linq,Expression Trees,假设我有一些C#代码,如下所示: var query1 = query.Where(x => x.BirthDate > now); var query2 = query.Where(x => x.EnrollmentDate > now); var query3 = query.Where(x => x.GraduationDate > now); 实际代码更复杂,但我使用的是一个简单的示例。我正在将此代码传递给实体框架 假设我看到这个,说,“这是不干燥的

假设我有一些C#代码,如下所示:

var query1 = query.Where(x => x.BirthDate > now);
var query2 = query.Where(x => x.EnrollmentDate > now);
var query3 = query.Where(x => x.GraduationDate > now);
实际代码更复杂,但我使用的是一个简单的示例。我正在将此代码传递给实体框架

假设我看到这个,说,“这是不干燥的”,然后我写了一个这样的函数

public IQueryable<Student> FilterAfterDate(IQueryable<Student> query,
    Expression<Func<Student, DateTime>> GetDateExpression, DateTime now)
{
    return query.Where(x => GetDateExpression(x) > now);
}
我不知道细节,但我相信解决方法可能是以某种方式使用我的
FilterAfterDate
,即
Expression
,并以某种方式将其与日期时间比较相结合,生成类型为
Expression
的表达式,以传递到
Where
函数,但是我不知道如何做到这一点。

使用,您可以这样编写您的方法(我更喜欢作为扩展方法):

您只需使用一个通用的
ExpressionVisitor
,它可以替换:

public static class ExpressionExt {
    /// <summary>
    /// Replaces an Expression (reference Equals) with another 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>
/// ExpressionVisitor to replace an Expression (that is Equals) with another 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);
}
您可以像使用LINQKit一样使用它。

这是我的解决方案:

public static class MyExtensions
{
    public static MethodInfo GetMethod<TSource, TResult>(this Expression<Func<TSource, TResult>> lambda)
        => (lambda?.Body as MethodCallExpression)?.Method ?? throw new ArgumentException($"Not a {nameof(MethodCallExpression)}.");

    private static readonly MethodInfo _miWhere = GetMethod((IQueryable<int> q) => q.Where(x => false)).GetGenericMethodDefinition();

    public static IQueryable<TSource> WhereGreaterThan<TSource, TCompare>(this IQueryable<TSource> source, Expression<Func<TSource, TCompare>> selector, Expression<Func<TCompare>> comparand)
    {
        var predicate = Expression.Lambda<Func<TSource, bool>>(Expression.GreaterThan(selector.Body, comparand.Body), selector.Parameters[0]);
        var where = Expression.Call(_miWhere.MakeGenericMethod(typeof(TSource)), source.Expression, predicate);
        return source.Provider.CreateQuery<TSource>(where);
    }
}

谢谢,@KirkWoll。我修好了。但长话短说,你必须做一些表达式树操作。我有一个用于为EF映射编写表达式的库,尽管它不适用于您的特定需求。这里有一个例子,不过你需要看看一些辅助文件,以获得完整的图片。这是最常见的处理方法,除了滚动你自己的。我的EF实现包括一个专门的
Invoke
替换EF,但它被封装在join代码中,可能很难遵循。我可以发布一些简单的东西。这听起来像是我在寻找的。可惜这样一个看似简单的任务竟然需要这样一件事。您是否愿意提供一个答案,说明如何使用LINQKit实现我想要的功能?我更喜欢自己滚动,尽管我在想,如果您现在必须将
传递给您的
过滤器AfterDate
,那么在这个简单的示例中,您实际上没有比原始代码获得任何东西,只是将
替换为
var q1 = query.FilterAfterDate(q => q.BirthDate, now);
var q2 = query.FilterAfterDate(q => q.EnrollmentDate, now);
var q3 = query.FilterAfterDate(q => q.GraduationDate, now);
public static class ExpressionExt {
    /// <summary>
    /// Replaces an Expression (reference Equals) with another 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>
/// ExpressionVisitor to replace an Expression (that is Equals) with another 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);
}
public static class StudentExt {
    public static IQueryable<Student> FilterAfterDate(this IQueryable<Student> query,
        Expression<Func<Student, DateTime>> GetDateExpression, DateTime now) {
        Expression<Func<DateTime,bool>> templateFn = x => x > now;
        var filterFn = Expression.Lambda<Func<Student,bool>>(templateFn.Body.Replace(templateFn.Parameters[0], GetDateExpression.Body), GetDateExpression.Parameters);

        return query.Where(filterFn);
    }
}
public static class MyExtensions
{
    public static MethodInfo GetMethod<TSource, TResult>(this Expression<Func<TSource, TResult>> lambda)
        => (lambda?.Body as MethodCallExpression)?.Method ?? throw new ArgumentException($"Not a {nameof(MethodCallExpression)}.");

    private static readonly MethodInfo _miWhere = GetMethod((IQueryable<int> q) => q.Where(x => false)).GetGenericMethodDefinition();

    public static IQueryable<TSource> WhereGreaterThan<TSource, TCompare>(this IQueryable<TSource> source, Expression<Func<TSource, TCompare>> selector, Expression<Func<TCompare>> comparand)
    {
        var predicate = Expression.Lambda<Func<TSource, bool>>(Expression.GreaterThan(selector.Body, comparand.Body), selector.Parameters[0]);
        var where = Expression.Call(_miWhere.MakeGenericMethod(typeof(TSource)), source.Expression, predicate);
        return source.Provider.CreateQuery<TSource>(where);
    }
}
var now = DateTime.Now;
var result = new[]
    {
        new { Item = "Past", Date = now.AddDays(-1) },
        new { Item = "Future", Date = now.AddDays(1) }
    }
    .AsQueryable()
    .WhereGreaterThan(x => x.Date, () => now)
    .Select(x => x.Item)
    .Single();
// "Future"