Entity Framework 为 WHERE 中的步骤序列查询相同的 table

Entity Framework query the same table for the sequence of steps in WHERE

我有以下 EF 代码优先 class 来跟踪机场人员的到达状态。每次检查记录都会插入到这个table中。以下是演示流程的步骤。

Landed -> FirstCheck Approved -> Clearance Approved -> Arrived
Landed -> FirstCheck Approved -> Clearance Approved -> Security Check -> Denied // This is the one I need to query
Landed -> FirstCheck Approved -> Clearance Approved -> Security Check -> Arrived

我需要找到 FirstCheck Approved 和 SecurityCheck 被拒绝的记录来追踪原因。

public class ArrivalStatusLog
{
    public ArrivalStatusLog();
    public int ArrivalStatusLogId { get; set; }
    public int PersonNumber{ get; set; }
    public DateTime CreationDate { get; set; }
    public string Status { get; set; }
}

EF查询

var denialPersons = await db.ArrivalStatusLogs
                            .Where(s => s.Status == "Denied") // Additional filter
                            .Select(x => x.PersonNumber)

对于具有其他状态的给定人员,如何对同一 table 中的其他记录进行 AND 条件处理?在我的例子中,我需要找到 Denied,然后是 FirstCheck Approved 和 Security Check。

您可以使用 .Any() 查找所有记录,其中存在同一人的另一条记录被拒绝的状态:

var denialPersons= await db.ArrivalStatusLogs
          .Where(s => db.ArrivalStatusLogs.Any(d => d.PersonNumber == s.PersonNumber && d.Status == "Denied")) // Additional filter
          .Select(x=> x.PersonNumber);

我希望 .Select() 在这里是多余的,事实上,您只需要原始记录,以及创建日期和状态,但为了以防万一,这就是您想要的。

生成的 SQL 类似于:

SELECT  PersonNumber
FROM    ArrivalStatusLogs AS s
WHERE   EXISTS
        (   SELECT  1
            FROM    ArrivalStatusLogs AS d
            WHERE   d.PersonNumber = s.PersonNumber
            AND     d.Status = 'Denied'
        );

如果您只想select您想要的第一个检查记录,那么您将需要进一步的过滤,例如

var denialPersons= await db.ArrivalStatusLogs
          .Where(s => s.Status == "FirstCheck Approved" && 
                        db.ArrivalStatusLogs.Any(d => d.PersonNumber == s.PersonNumber 
                                    && d.Status == "Denied")) // Additional filter
          .Select(x=> x.PersonNumber);    

相当于:

SELECT  PersonNumber
FROM    ArrivalStatusLogs AS s
WHERE   s.Status = 'FirstCheck Approved'
AND     EXISTS
        (   SELECT  1
            FROM    ArrivalStatusLogs AS d
            WHERE   d.PersonNumber = s.PersonNumber
            AND     d.Status = 'Denied'
        );