如何在复杂的计算数据基础上正确地执行带有子句的LINQ查询

本文关键字:执行 行带 子句 查询 LINQ 正确地 基础上 复杂 计算 数据 | 更新日期: 2023-09-27 18:01:19

我对LINQ to Entities和LINQ to SQL有相当丰富的经验,但是这个查询让我头疼。

我需要一些指导如何成功地创建一个干净的LINQ到实体查询,当它有基于计算列的条件子句,当将数据投影到对象时,也要使用计算列。

投影结果类如下:

public class FilterClientsResult
{
    public enum ClientType
    {
        ALL,
        LIST,
        VIP
    }
    public int ClientId { get; set; }        
    public string Document { get; set; }
    public string Email { get; set; }
    public string LastName { get; set; }
    public string Name { get; set; }
    public ClientType Type { get; set; }
    public int Visits { get; set; }
}

那么数据来自一个主要来源和三个补充来源。

主要来源是Client实体,在其所有属性中,它具有所有预测属性,除了最后两个(类型和访问)

其他来源是:

Subscription,其中一个Client可以有多个Subscription

ClientAccess,其中1个Subscription可以有多个ClientAccess

GuestListClient,其中一个Client可以有多个GuestListClient

因此,当Client同时与ClientAccessGuestListClient实体相关时,ClientType Type属性被设置为FilterClientsResult.ClientType.ALL

Client只与ClientAccess实体相关时设置为FilterClientsResult.ClientType.VIP,当Client只与GuestListClient实体相关时设置为FilterClientsResult.ClientType.LIST

则设置Visits属性为Client所关联的ClientAccessGuestListClient实体之和。

所以我需要的查询应该能够通过FilterClientsResult.ClientType过滤客户端,但也预测FilterClientsResult.ClientType

我还需要通过Visits范围进行过滤,但也要投影Visits值。

那么,构建这样一个查询的最佳方法是什么呢

如何在复杂的计算数据基础上正确地执行带有子句的LINQ查询

使用let关键字将中间结果存储为变量,这在查询语法中效果最好:

from c in Clients
let vipCount = c.Subscriptions.SelectMany(s => s.ClientAccesses).Count()
let listCount = c.GuestListClients.Count()
select new FilterClientsResult {
        c.ClientId,
        ...
        Type = vipCount > 0 ? listCount > 0 ? ClientType.ALL 
                                            : ClientType.VIP 
                            : listCount == 0 ? 0 
                                             : ClientType.LIST,
        Visits  = vipCount + listCount
    }

(未检查语法)

注意ClientType enum必须为EF所知,否则您首先必须投影所需的属性,其中Typeint。然后,在AsEnumerable()之后,将int类型强制转换为enum类型。

还要注意,当两个计数都为0时,存在一个不确定的值。