#c# #.net #linq #asp.net-core
Вопрос:
Я где-то делаю что-то не так, просто не знаю где.
Я пытаюсь реализовать RANK()
функцию окна в своем запросе LINQ.
Ниже, пожалуйста, найдите SQL-запрос:
select
tl.TransferLinkId
,tl.TransferLinkTypeId
,tl.PrimaryTransferId
,tl.SecondaryTransferId
,tl.UpdatedDate
,COUNT(tl.SecondaryTransferId) OVER (Partition by tl.SecondaryTransferId) AS DuplicateCount
,RANK() OVER (PARTITION BY tl.TransferLinkTypeId, tl.SecondaryTransferId ORDER BY tl.UpdatedDate DESC, tl.TransferLinkId) as RankVal
from TransferLink tl WITH (NOLOCK)
join TransferLinkType tlt WITH (NOLOCK) on (tl.TransferLinkTypeId = tlt.TransferLinkTypeId and tlt.EnumTransferLinkType = 'Deviance')
--where
-- tl.Archived=0
and (
PrimaryTransferId in (select TransferId from @AllTransferIds)
or SecondaryTransferId in (select TransferId from @AllTransferIds)
)
UNION ALL
select
tl.TransferLinkId
,tl.TransferLinkTypeId
,tl.PrimaryTransferId
,tl.SecondaryTransferId
,tl.UpdatedDate
,COUNT(tl.PrimaryTransferId) OVER (Partition by tl.PrimaryTransferId) AS DuplicateCount
,RANK() OVER (PARTITION BY tl.TransferLinkTypeId, tl.PrimaryTransferId ORDER BY tl.UpdatedDate DESC, tl.TransferLinkId) as RankVal
from TransferLink tl WITH (NOLOCK)
join TransferLinkType tlt WITH (NOLOCK) on (tl.TransferLinkTypeId = tlt.TransferLinkTypeId and tlt.EnumTransferLinkType = 'Deviance')
--where
-- tl.Archived=0
and (
PrimaryTransferId in (select TransferId from @AllTransferIds)
or SecondaryTransferId in (select TransferId from @AllTransferIds)
)
Ниже приведена упрощенная версия реализации моего РАНГА.
var transferLinks = (from tl in _repo.Context.TransferLink
join tlt in _repo.Context.TransferLinkType on new { TLinkId = tl.TransferLinkTypeId, EType = "Deviance" } equals new { TLinkId = tlt.TransferLinkTypeId, EType = tlt.EnumTransferLinkType }
let duplicateCount = _repo.Context.TransferLink.Where(tl1 => tl1.SecondaryTransferId != null amp;amp; tl.SecondaryTransferId != null amp;amp;
tl1.SecondaryTransferId == tl.SecondaryTransferId.Value).Count()
where
(allTransferIds.Contains(tl.PrimaryTransferId) || allTransferIds.Contains(tl.SecondaryTransferId)) amp;amp;
!tl.Archived
select new
{
TransferLinkId = tl.TransferLinkId,
TransferLinktypeId = tl.TransferLinkTypeId,
PrimaryTransferId = tl.PrimaryTransferId,
SecondaryTransferId = tl.SecondaryTransferId,
DuplicateCount = duplicateCount, //COUNT(tl.SecondaryTransferId) OVER (Partition by tl.SecondaryTransferId) AS DuplicateCount
UpdatedDate = tl.UpdatedDate,
RankVal = _repo.Context.TransferLink
.Where(tl1 => tl1.SecondaryTransferId != null amp;amp; tl1.SecondaryTransferId == tl.SecondaryTransferId)
.OrderByDescending(tl1 => tl1.UpdatedDate)
.ThenBy(tl1 => tl1.TransferLinkId)
.GroupBy(tl1 => new { tl1.TransferLinkTypeId, tl1.SecondaryTransferId })
.SelectMany(g => g.Select((x, i) => new { data = g.Key, index = i 1 }))
.First(g => g.data.SecondaryTransferId == tl.SecondaryTransferId amp;amp; g.data.TransferLinkTypeId == tl.TransferLinkTypeId).index
}).AsEnumerable().Union(
from tl in _repo.Context.TransferLink
join tlt in _repo.Context.TransferLinkType on new { TLinkId = tl.TransferLinkTypeId, EType = "Deviance" } equals new { TLinkId = tlt.TransferLinkTypeId, EType = tlt.EnumTransferLinkType }
let duplicateCount = _repo.Context.TransferLink.Where(tl1 => tl1.PrimaryTransferId.Value == tl.PrimaryTransferId.Value amp;amp;
tl.PrimaryTransferId != null amp;amp; tl1.PrimaryTransferId != null).Count()
where
(allTransferIds.Contains(tl.PrimaryTransferId) || allTransferIds.Contains(tl.SecondaryTransferId)) amp;amp;
!tl.Archived
select new
{
TransferLinkId = tl.TransferLinkId,
TransferLinktypeId = tl.TransferLinkTypeId,
PrimaryTransferId = tl.PrimaryTransferId,
SecondaryTransferId = tl.SecondaryTransferId,
DuplicateCount = duplicateCount, //COUNT(tl.SecondaryTransferId) OVER (Partition by tl.SecondaryTransferId) AS DuplicateCount
UpdatedDate = tl.UpdatedDate,
RankVal = _repo.Context.TransferLink
.Where(tl1 => tl1.PrimaryTransferId != null amp;amp; tl1.PrimaryTransferId == tl.SecondaryTransferId)
.OrderByDescending(tl1 => tl1.UpdatedDate)
.ThenBy(tl1 => tl1.TransferLinkId)
.GroupBy(tl1 => new { tl1.TransferLinkTypeId, tl1.PrimaryTransferId })
.SelectMany(g => g.Select((x, i) => new { data = g.Key, index = i 1 }))
.First(g => g.data.PrimaryTransferId == tl.PrimaryTransferId amp;amp; g.data.TransferLinkTypeId == tl.TransferLinkTypeId).index
}).ToList();
Ниже приведен результат SQL-запроса:
И результаты моего запроса LINQ:
{ TransferLinkId = 1868745, TransferLinktypeId = 3, PrimaryTransferId = , SecondaryTransferId = 44403182, DuplicateCount = 2, UpdatedDate = 2021/08/16 18:23:19, RankVal = 1 }
{ TransferLinkId = 1868751, TransferLinktypeId = 3, PrimaryTransferId = 44403188, SecondaryTransferId = 44403182, DuplicateCount = 2, UpdatedDate = 2021/08/16 19:03:25, RankVal = 1 }
{ TransferLinkId = 1868745, TransferLinktypeId = 3, PrimaryTransferId = , SecondaryTransferId = 44403182, DuplicateCount = 0, UpdatedDate = 2021/08/16 18:23:19, RankVal = 0 }
{ TransferLinkId = 1868751, TransferLinktypeId = 3, PrimaryTransferId = 44403188, SecondaryTransferId = 44403182, DuplicateCount = 1, UpdatedDate = 2021/08/16 19:03:25, RankVal = 1 }
Счетчик дубликатов вычисляется правильно, но я, кажется, делаю что-то не так с RankVal.
Есть идеи, чего мне не хватает?
Комментарии:
1. Может быть, лучше получить linq2db.EntityFrameworkCore и использовать оконные функции в LINQ? Это должно быть намного быстрее, чем подражание им.
2. Какую версию EF Core вы используете? Вы можете использовать
FromSqlRaw
/FromSqlInterpolated
и не переписывать запрос.3. Также вы можете попробовать ELINQ