我正在嘗試實作一個Linq to SQL的運算子(EF核心)
q.TakeDistinct(n, src => src.Field)
這樣它就可以從q中回傳前n個元素,只計算不同的Field
基本上我想要一個Take,不計算在Field中沒有不同的元素
例如:
Job Status
10 start
10 progress
10 alert
10 done
12 start
12 error
12 done
32 開始
32 info
32 done
然后
ctx.Table.TakeDistinct(2, v => v.Job)/code>
將回傳:
10 start
10 progress
10 alert
10 done
12 start
12 error
12 done
我嘗試了Take和Distinct的各種組合,但沒有任何收獲,感謝任何線索。
注意,我正在尋找能夠通過Linq-to-SQL(不是在記憶體中處理)轉化為合理有效的SQL的東西
。編輯:
這樣做的目的是:
ctx.Table.Where(z =>
表.Select(x => x.Field).Distinct().Take(n)
.包含(z.Field)
);
如果是這樣,真的很慢(在LinqPad中)......是否有更好的方法?
uj5u.com熱心網友回復:
在SQL中,我將會看到一個WHERE IN子查詢。
SELECT JobId, Status
FROM 作業
WHERE Status In (SELECT DISTINCT TOP 2 Status FROM Jobs)
對LinqToSQL沒有太多的經驗,但這可能直接起作用:
var TakeJobs = db.Jobs.Select(j => j.JobId).Distinct().Take(2) 。
var entries = db.Jobs.Where(j => TakeJobs.Contains(j.JobId) )。
顯然,用一個連接到子查詢的方法可能會更便宜。 我不確定這在Linq中的表現如何。
SELECT JobId, Status FROM Jobs j
RIGHT JOIN (SELECT DISTINCT TOP 2 JobId FROM Jobs) t ON t.JobId = j.JobId。
uj5u.com熱心網友回復:
我理解你的想法。我寫了這個擴展方法來實作。 但它需要優化,因為濫用LinQ可能會影響性能。
public static IEnumerable< T> TakeDistinct< T, TProperty> (this IEnumerable< T> source, int take, Expression<Func<T, TProperty>> distinctBy)。
{
var orderList = source.AsQueryable().GroupBy(distinctBy).OrderBy(x=>x.Key).Take(take).Select(x=>x.Key).ToList()。
var mappingFunc = distinctBy.Compile();
return source.Where(x => orderList.Contains(mappingFunc.Invoke(x))。
}
static void Main()
{
var jobLines = @"10 start
10 進度
10 警報
10 完成
12 開始
12 錯誤
12 完成
32 開始
32 資訊
32 done"。
var jobs = jobLines.Split('
').Select(line =>
{
var splited = line.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries) 。
return new JobItem
{
Job = Convert.ToInt32(splitited[0])。
狀態 = splited[1].
};
});
var newJobs = jobs.TakeDistinct(2, x => x.Job) 。
foreach (var job in newJobs)
{
Console.WriteLine($"{job.Job} - {job.Status}") 。
}
Console.ReadLine()。
}
class JobItem; } Console.ReadLine(; }
{
public int Job { get; set; }
public string Status { get; set; }
}
public static IEnumerable< T> TakeDistinct< T, TProperty> (this IEnumerable< T> source, int take, Expression<Func<T, TProperty>> distinctBy)。
{
var orderList = source.AsQueryable().GroupBy(distinctBy).OrderBy(x=>x.Key).Take(take).Select(x=>x.Key).ToList()。
var mappingFunc = distinctBy.Compile();
return source.Where(x => orderList.Contains(mappingFunc.Invoke(x))。
}
--- UPDATED----
這次更新是為了支持LinQ到SQL
public static IQueryable< T> TakeDistinct< T, TProperty> (this IQueryable< T> source, int take, Expression<Func<T, TProperty>> distinctBy)。
{
var orderList = source.AsQueryable().GroupBy(distinctBy).OrderBy(x => x.Key).Take(take).SelectMany(x => x)。
return orderList;
}
------更新的----
我從上面的陳述句中添加了生成的SQL。
我已經創建了名為JobItems的假表,列。Id, Job 和 Status
SELECT
[Extent2].[Id] AS [Id]。
[Extent2].[Job] AS [Job]。
[Extent2].[Status] AS [Status].
FROM (SELECT TOP (2) [Distinct1].[Job] AS [Job]
FROM ( SELECT DISTINCT
[Extent1].[Job]作為[Job]。
FROM [dbo].[JobItems] AS [Extent1]
) 作為[Distinct1]。
ORDER BY [Distinct1].[Job] ASC ) 作為[Limit1] 。
INNER JOIN [dbo].[JobItems] AS [Extent2] ON [Limit1].[Job] = [Extent2].[Job] 。
uj5u.com熱心網友回復:
下面的擴展生成運算式樹,使Distinct().Take(x)并生成對原始查詢的連接。它還接受x => new { x.Id, x.Id2 }引數作為獨立鍵。
public static class QueryableExtensions
{
public static IQueryable< T> TakeDistinct< T, TKey>(this IQueryable< T> source, int take,
Expression<Func<T, TKey>> distinctBy)。
{
var distinctQuery = source.Select(distinctBy).Distinct().Take(take)。
var distinctParam = Expression.Parameter(typeof(TKey), "d"/span>)。
var entityParam = distinctBy.Parameters[0] 。
var mapping = MapMembers(distinctBy.Body, distinctParam) .ToList();
var whereExpr = mapping.Select(t => Expression.Equal(t.Item1, t.Item2))
.Aggregate(Expression.AndAlso)。
var whereLambda = Expression.Lambda(whereExpr, entityParam)。
var selectManySelector =
Expression.Lambda(
Expression.Convert(
Expression.Call(typeof(Queryable), nameof(Queryable.Where), new[ ] { typeof(T) },
source.Expression,
whereLambda)。)
typeof(IEnumerable< T>)
),
差異化引數(distinctParam
);
var selectManyQuery = Expression.Call(typeof(Queryable), nameof(Queryable.SelectMany) 。
new[] { typeof(TKey), typeof(T) }, distinctQuery.Expression, selectManySelector) 。
return source.Provider.CreateQuery<T>(selectManyQuery)。
}
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。
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/309867.html
標籤:
上一篇:物體框架一對多關系不作業
下一篇:轉換為RDD失敗

