根据多个连接列获取按最新更改排序的列表

问题描述 投票:0回答:1

我有一个人员表和其他相关表 - 订单、联系人历史记录、地址和电子邮件。 Persons 表包含基本详细信息 - 姓名、出生日期和一些其他属性。 表的类包含 Persons 表引用的表的集合,因此,我可以在需要的过滤器或引用的查询中使用它们。

所有这些表都具有在每次更新时设置的

Updated
属性。

我需要返回一页按最新更改降序排列的结果。

因此,如果有人更改某人的地址、更改姓名或联系该人,所有这些操作都应将该人移至顶部。

我的查询的基本部分看起来像

var result = await _context
                .Persons
                .Include(p => p.Addresses)
                .Include(p => p.Emails)
                .Include(p => p.Orders)
                .Include(p => p.ContactHistory)
                .OrderByDescending(p => p.Updated)
                .AsSplitQuery()
                .AsNoTracking()
                .ToArrayAsync();

我需要更改

OrderByDescending(p => p.Updated)
以包含其他表格。

我不能使用

ThenBy
,因为这不起作用 - 只有当所有先前的日期都相同时,接下来的每个部分才会对数据进行排序。

我需要类似

OrderByDescending(p => Max(p.Updated, p.Addresses.Updated, p.Emails.Updated ... and so on))

的东西

如果找不到解决方案,我正在考虑编写一个 SQL Server 函数并使用 EF Core 从 C# 代码调用它。

我将如何在 T-SQL 中执行此操作的示例:

select distinct top 10 p.* from persons p
  inner join Addresses a on p.id = a.PersonId
  inner join Emails e on p.id = e.PersonId
  inner join Orders o on p.id = o.PersonId
  inner join ContactHistory c on p.id = c.PersonId
order by (select max(updated) from (values(p.Updated), (a.Updated),
  (e.Updated), (o.Updated), (c.Updated)) t(updated))

不幸的是,这不是最有效的查询,但业务需求需要这种逻辑。

我也愿意接受有关如何解决这个问题的其他建议 - 也许存在我不知道的模式或其他东西。

我很确定这个任务不是唯一的,这个问题已经在这里被问过很多次了,但我找不到关键字来发现它,所以,我真诚地为可能的重复而提前道歉。

c# entity-framework-core
1个回答
0
投票

尝试以下查询。它为每个人准备最后更新的信息。然后加入您的原始查询并做出适当的顺序。

// append filters
var personsQuery = _context.Persons;

var orderQuery = 
    from p in personsQuery
    from e in p.Emails
    from o in p.Orders
    from h in p.ContactHistory
    group new { p, e, o, h } by p.Id into g
    select new 
    {
        PersonId = g.Key,
        LastUpdated = g.Max(x => Math.Max(x.p.Updated, Math.Max(x.e.Updated, Math.Max(x.o.Updated, x.h.Updated))))
    }

orderQuery = orderQuery
    .OrderByDescending(p => p.LastUpdate)
    .Take(10);

var query = personsQuery
    .Include(p => p.Addresses)
    .Include(p => p.Emails)
    .Include(p => p.Orders)
    .Include(p => p.ContactHistory);

query = 
    from q in query
    join o in orderQuery on q.Id equals o.PersonId
    orderby o.LastUpdated descending
    select q;


var result = await query    
    .AsSplitQuery()
    .AsNoTracking()
    .ToArrayAsync();

© www.soinside.com 2019 - 2024. All rights reserved.