gpt4 book ai didi

linq - 如何转换此 linq 表达式?

转载 作者:行者123 更新时间:2023-12-05 01:07:07 25 4
gpt4 key购买 nike

假设我有一个要查询并应用排名的实体:

public class Person: Entity
{
public int Id { get; protected set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
}

在我的查询中,我有以下内容:
Expression<Func<Person, object>> orderBy = x => x.Name;

var dbContext = new MyDbContext();

var keyword = "term";
var startsWithResults = dbContext.People
.Where(x => x.Name.StartsWith(keyword))
.Select(x => new {
Rank = 1,
Entity = x,
});
var containsResults = dbContext.People
.Where(x => !startsWithResults.Select(y => y.Entity.Id).Contains(x.Id))
.Where(x => x.Name.Contains(keyword))
.Select(x => new {
Rank = 2,
Entity = x,
});

var rankedResults = startsWithResults.Concat(containsResults)
.OrderBy(x => x.Rank);

// TODO: apply thenby ordering here based on the orderBy expression above

dbContext.Dispose();

在使用 Rank 选择匿名对象之前,我尝试对结果进行排序。属性,但排序最终会丢失。似乎 linq to entity 丢弃了单独集合的排序,并在 Concat 期间转换回自然排序。和 Union .

我认为我可以做的是动态转换 orderBy 中定义的表达式。来自 x => x.Name 的变量至 x => x.Entity.Name ,但我不确定如何:
if (orderBy != null)
{
var transformedExpression = ???
rankedResults = rankedResults.ThenBy(transformedExpression);
}

我如何才能使用 Expression.Lambda包装 x => x.Name进入 x => x.Entity.Name ?当我硬编码时 x => x.Entity.NameThenBy我得到了我想要的订单,但 orderBy由查询的调用类提供,因此我不想对其进行硬编码。我在上面的示例中对其进行了硬编码,只是为了简化说明。

最佳答案

这应该有帮助。但是,您将不得不具体化匿名类型才能使其工作。我的 LinqPropertyChain 无法使用它,因为它很难创建 Expression<Func<Anonymous, Person>>虽然它仍然是匿名的。

Expression<Func<Person, object>> orderBy = x => x.Name;

using(var dbContext = new MyDbContext())
{
var keyword = "term";
var startsWithResults = dbContext.People
.Where(x => x.Name.StartsWith(keyword))
.Select(x => new {
Rank = 1,
Entity = x,
});
var containsResults = dbContext.People
.Where(x => !startsWithResults.Select(y => y.Entity.Id).Contains(x.Id))
.Where(x => x.Name.Contains(keyword))
.Select(x => new {
Rank = 2,
Entity = x,
});


var rankedResults = startsWithResults.Concat(containsResults)
.OrderBy(x => x.Rank)
.ThenBy(LinqPropertyChain.Chain(x => x.Entity, orderBy));

// TODO: apply thenby ordering here based on the orderBy expression above

}

public static class LinqPropertyChain
{

public static Expression<Func<TInput, TOutput>> Chain<TInput, TOutput, TIntermediate>(
Expression<Func<TInput, TIntermediate>> outter,
Expression<Func<TIntermediate, TOutput>> inner
)
{

Console.WriteLine(inner);
Console.WriteLine(outter);
var visitor = new Visitor(new Dictionary<ParameterExpression, Expression>
{
{inner.Parameters[0], outter.Body}
});

var newBody = visitor.Visit(inner.Body);
Console.WriteLine(newBody);
return Expression.Lambda<Func<TInput, TOutput>>(newBody, outter.Parameters);
}

private class Visitor : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, Expression> _replacement;

public Visitor(Dictionary<ParameterExpression, Expression> replacement)
{
_replacement = replacement;
}

protected override Expression VisitParameter(ParameterExpression node)
{
if (_replacement.ContainsKey(node))
return _replacement[node];
else
{
return node;
}
}
}
}

想出一种使用较少的显式泛型来做到这一点的方法。
Expression<Func<Person, object>> orderBy = x => x.Name;
Expression<Func<Foo, Person>> personExpression = x => x.Person;

var helper = new ExpressionChain(personExpression);
var chained = helper.Chain(orderBy).Expression;


// Define other methods and classes here
public class ExpressionChain<TInput, TOutput>
{
private readonly Expression<Func<TInput, TOutput>> _expression;
public ExpressionChain(Expression<Func<TInput, TOutput>> expression)
{
_expression = expression;
}

public Expression<Func<TInput, TOutput>> Expression { get { return _expression; } }

public ExpressionChain<TInput, TChained> Chain<TChained>
(Expression<Func<TOutput, TChained>> chainedExpression)
{
var visitor = new Visitor(new Dictionary<ParameterExpression, Expression>
{
{_expression.Parameters[0], chainedExpression.Body}
});
var lambda = Expression.Lambda<Func<TInput, TOutput>>(newBody, outter.Parameters);
return new ExpressionChain(lambda);
}

private class Visitor : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, Expression> _replacement;

public Visitor(Dictionary<ParameterExpression, Expression> replacement)
{
_replacement = replacement;
}

protected override Expression VisitParameter(ParameterExpression node)
{
if (_replacement.ContainsKey(node))
return _replacement[node];
else
{
return node;
}
}
}
}

关于linq - 如何转换此 linq 表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19031493/

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