[英]Convert into LINQ expression tree
我有一個 LINQ 語句我想將它轉換成表達式樹
public class tblEmpLocation
{
public uint EmpLocationId { get; set; }
public uint? EmpId { get; set; }
public uint? LocationId { get; set; }
public DateTime EffectiveDt { get; set; } = DateTime.Now;
}
我們有員工位置類,基本上有員工 ID 和位置 ID 的位置。
public class temptable
{
public uint Id{ get; set; }
public DateTime EffectiveDt { get; set; }
}
我們有一個臨時類,它基本上包含作為示例類的 ID 和有效日期。 現在我們有類似的表,比如員工部門、員工工資等,所以我們想創建一個 linq 擴展,基本上將類作為輸入並獲得所需的結果
List<tblEmpLocation> tbls = new List<tblEmpLocation>();
var data=tbls.GroupBy(p => p.EmpId).Select(q => new temptable{ Id=q.Key, EffectiveDt=q.Max(r => r.EffectiveDt) });
感謝幫助
這是DistinctBy
方法的通用實現,它返回組的最后一條記錄。
進行以下調用時的示意圖:
query = query.DistinctBy(e => e.EmpId, e => e.EffectiveDt);
// or with complex keys
query = query.DistinctBy(e => new { e.EmpId, e.Other }, e => new { e.EffectiveDt, e.SomeOther});
或全動態
query = query.DistinctBy("EmpId", "EffectiveDt");
函數生成以下查詢:
query =
from d in query.Select(d => d.EmpId).Distinct()
from e in query
.Where(e => e.EmpId == d)
.OrderByDescending(e => e.EffectiveDt)
.Take(1)
select e;
或者使用復雜的鍵:
query =
from d in query.Select(d => new { d.EmpId, d.Other }).Distinct()
from e in query
.Where(e => e.EmpId == d.EmpId && e.Other == d.Other)
.OrderByDescending(e => e.EffectiveDt)
.ThenByDescending(e => e.SomeOther)
.Take(1)
select e;
和實現:
public static class QueryableExtensions
{
public static IQueryable<T> DistinctBy<T>(
this IQueryable<T> source,
string distinctPropName,
string maxPropName)
{
var entityParam = Expression.Parameter(typeof(T), "e");
var distinctBy = Expression.Lambda(MakePropPath(entityParam, distinctPropName), entityParam);
var maxBy = Expression.Lambda(MakePropPath(entityParam, maxPropName), entityParam);
var queryExpression = Expression.Call(typeof(QueryableExtensions), nameof(QueryableExtensions.DistinctBy),
new[] { typeof(T), distinctBy.Body.Type, maxBy.Body.Type },
Expression.Constant(source),
Expression.Quote(distinctBy),
Expression.Quote(maxBy));
var executionLambda = Expression.Lambda<Func<IQueryable<T>>>(queryExpression);
return executionLambda.Compile()();
}
public static IQueryable<T> DistinctBy<T, TKey, TMax>(
this IQueryable<T> source,
Expression<Func<T, TKey>> distinctBy,
Expression<Func<T, TMax>> maxBy)
{
var distinctQuery = source.Select(distinctBy).Distinct();
var distinctParam = Expression.Parameter(typeof(TKey), "d");
var entityParam = distinctBy.Parameters[0];
var mapping = MapMembers(distinctBy.Body, distinctParam).ToList();
var orderParam = maxBy.Parameters[0];
var oderMapping = CollectMembers(maxBy.Body).ToList();
var whereExpr = mapping.Select(t => Expression.Equal(t.Item1, t.Item2))
.Aggregate(Expression.AndAlso);
var whereLambda = Expression.Lambda(whereExpr, entityParam);
// d => query.Where(x => d.distinctBy == x.distinctBy).Take(1)
Expression selectExpression = Expression.Call(typeof(Queryable), nameof(Queryable.Where), new[] { typeof(T) },
source.Expression,
whereLambda);
// prepare OrderByPart
for (int i = 0; i < oderMapping.Count; i++)
{
var orderMethod = i == 0 ? nameof(Queryable.OrderByDescending) : nameof(Queryable.ThenByDescending);
var orderItem = oderMapping[i];
selectExpression = Expression.Call(typeof(Queryable), orderMethod, new[] { typeof(T), orderItem.Type },
selectExpression, Expression.Lambda(orderItem, orderParam));
}
// Take(1)
selectExpression = Expression.Call(typeof(Queryable), nameof(Queryable.Take), new[] { typeof(T) },
selectExpression,
Expression.Constant(1));
var selectManySelector =
Expression.Lambda<Func<TKey, IEnumerable<T>>>(selectExpression, distinctParam);
var selectManyQuery = Expression.Call(typeof(Queryable), nameof(Queryable.SelectMany),
new[] { typeof(TKey), typeof(T) }, distinctQuery.Expression, selectManySelector);
return source.Provider.CreateQuery<T>(selectManyQuery);
}
static Expression MakePropPath(Expression objExpression, string path)
{
return path.Split('.').Aggregate(objExpression, Expression.PropertyOrField);
}
private static IEnumerable<Tuple<Expression, Expression>> MapMembers(Expression expr, Expression projectionPath)
{
switch (expr.NodeType)
{
case ExpressionType.New:
{
var ne = (NewExpression)expr;
for (int i = 0; i < ne.Arguments.Count; i++)
{
foreach (var e in MapMembers(ne.Arguments[i], Expression.MakeMemberAccess(projectionPath, ne.Members[i])))
{
yield return e;
}
}
break;
}
default:
yield return Tuple.Create(projectionPath, expr);
break;
}
}
private static IEnumerable<Expression> CollectMembers(Expression expr)
{
switch (expr.NodeType)
{
case ExpressionType.New:
{
var ne = (NewExpression)expr;
for (int i = 0; i < ne.Arguments.Count; i++)
{
yield return ne.Arguments[i];
}
break;
}
default:
yield return expr;
break;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.