实体框架条件选择

发布于 2025-01-14 17:34:05 字数 696 浏览 2 评论 0原文

Id1Id2DateState
112022-03-14Failed
112022-03-15Success

鉴于上面的数据库表,我正在尝试编写 EF 查询,其中我们显示每个 Id Id2 组合的最新记录,但失败将永远保留在列表中。只有上周的成功才会被包括在内。

我认为我正在努力解决的部分是,如果给定的 Id Id2 组合存在失败,但未来会成功,则不应返回失败。

关于从哪里开始有什么建议吗?上一次尝试尝试执行某项操作

.Where(x => x.state == 'Failed' || x.CreatedOn > DateTime.Now.AddDays(-7)

,但 10 天前失败,随后 9 天前成功,已列出。 (这种情况应该不返回任何内容,因为成功已经在一周前了)

基本上所有失败,除了后来成功的 UNION 与过去 2 天的成功。 这可能吗?我从来没有在两个表之间的链接上花费这么长时间。

Id1Id2DateState
112022-03-14Failed
112022-03-15Success

Given the above database table, I am trying to write EF query where we show the latest record for each Id Id2 combo but failures will stay listed forever. Successes will only be included if it was in the last week.

The part I think I am struggling with is that If a failure exists for a given Id Id2 combo, but has a future success that failure shouldn't be returned.

Any suggestions on where to begin? The previous attempt tried to do a

.Where(x => x.state == 'Failed' || x.CreatedOn > DateTime.Now.AddDays(-7)

but a fail 10 days ago followed by a success 9 days ago was being listed. (This case should return nothing since the success was over a week ago)

Basically all fails except where a later success UNION with success last 2 days.
Is this even possible? I've never spent this long on a linq between 2 tables.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

变身佩奇 2025-01-21 17:34:05

首先一个问题:如果最近的状态是失败,是否只想报告自上次成功以来的失败?换句话说,对于序列{失败,失败,成功,失败,失败},您只想报告最后两个失败吗?我假设,是的。

在我看来,您首先需要按 Id2 进行分组,并为每个组计算两件事:

  1. 最新状态是什么。
  2. 最近一次成功的日期是哪一天?

由此,您可以选择该组的成员,其中:

  1. LatestState =“Success”且 Date = LateSuccessDate,或
  2. State =“Failed”且(LatestSuccessDate 为 null 或 Date > LateSuccessDate)

类似

Data
    .Where(r => r.CreatedOn >= DateTime.Now.AddDays(-7))
    .GroupBy(r => r.Id2)
    .SelectMany(grp => new {
        var latestState = grp
            .OrderByDescending(r => r.CreatedOn)
            .Select(r => r.State)
            .First(),
        var latestSuccessDate = grp
            .OrderByDescending(r => r.CreatedOn)
            .Where(r => r.State = 'Success')
            .Select(r => r.CreatedOn)
            .FirstOrDefault();
        return grp
            .Where(r =>
                (latestState == "Success" && r.CreatedOn == latestSuccessDate)
                || (r.State == "Failure" && (latestSuccessDate == null || r.CreatedOn > latestSuccessDate))
            );
    });

免责声明的内容 - 以上未选中,并且语法上可能不是100%正确,但传达了我的想法。我确信还有优化的空间,例如预先订购每个组的成员。

我希望上面的代码能够完成内存中的大部分工作。我不确定是否可以将其编码为可转换为服务器端 SQL 查询的形式。比我更有技能的人可能会提供解决方案。目标是生成如下内容:

SELECT D.*
FROM (
    -- Select latest state per group
) LS
LEFT JOIN (
    -- Select the latest success date per group
) LSD
    ON LSD.Id2 = LS.Id2
JOIN DATA D
    ON D.Id2 = LS.Id2
WHERE -- Other conditions 

First a question: If the latest state is a failure, do you only want to report the failures since the last success? In other words for the sequence {Failure, Failure, Success, Failure, Failure} do you only want to report the last two Failures? I will assume, yes.

It seems to me that you first need to group by Id2 and calculate two things for each group:

  1. What was the latest state.
  2. What was the date of the latest success.

From that, you can select members of the group where either:

  1. The LatestState = "Success" and Date = LatestSuccessDate, or
  2. State = "Failed" and (LatestSuccessDate is null or Date > LatestSuccessDate)

Something like

Data
    .Where(r => r.CreatedOn >= DateTime.Now.AddDays(-7))
    .GroupBy(r => r.Id2)
    .SelectMany(grp => new {
        var latestState = grp
            .OrderByDescending(r => r.CreatedOn)
            .Select(r => r.State)
            .First(),
        var latestSuccessDate = grp
            .OrderByDescending(r => r.CreatedOn)
            .Where(r => r.State = 'Success')
            .Select(r => r.CreatedOn)
            .FirstOrDefault();
        return grp
            .Where(r =>
                (latestState == "Success" && r.CreatedOn == latestSuccessDate)
                || (r.State == "Failure" && (latestSuccessDate == null || r.CreatedOn > latestSuccessDate))
            );
    });

Disclaimer - The above is unchecked and might not be 100% syntactically correct, but conveys my ideas. There are also I'm sure room for optimizations, such as pre-ordering the members of each group.

I expect that the above will perform most of the work in memory. I am not sure if this can be coded in a form that will translate to a server side SQL query. Someone with more skills than I may offer a solution. The goal would be to generate something like:

SELECT D.*
FROM (
    -- Select latest state per group
) LS
LEFT JOIN (
    -- Select the latest success date per group
) LSD
    ON LSD.Id2 = LS.Id2
JOIN DATA D
    ON D.Id2 = LS.Id2
WHERE -- Other conditions 
欢烬 2025-01-21 17:34:05

我不确定这是否可以转换为 EF 查询,但我想我会发布它以防万一(或者万一它可以提供一些灵感)。这是一种 Linq to Objects 方法,应该会产生所需的输出。

如果您的类定义如下:

public class Item
{
    public int Id1 { get; set; }
    public int Id2 { get; set; }
    public DateTime Date { get; set; }
    public State State { get; set; }
}

public enum State
{
    Undefined,
    Success,
    Failed
}

并且您的项目存储在 Item 集合中,您可以:

  1. 项目进行分组
  2. Id1Id2对 在每个组中,选择具有最新 Date 值的一项(使用 .MaxBy())
    • ( .MaxBy( * ) 也可以替换为 .OrderByDescending( * ).First() )
  3. 过滤现在不同的Id1 -and-Id2 项目集合仅保留 State = Failed 或不少于一周的项目

对于项目集合 List; items,它可以按如下方式实现:

List<Item> result = items
    .GroupBy(item => ( item.Id1, item.Id2 ))
    .Select(gr => gr.MaxBy(item => item.Date))
    .Where(item =>
          item.State == State.Failed ||
          item.Date > DateTime.Now.AddDays(-7))
    .ToList();

示例小提琴此处

I am not sure this is translatable to an EF query, but thought I'd post it in case it is (or in case it could provide some inspiration). This is a Linq to Objects approach that should produce the desired output.

If your class is defined as follows:

public class Item
{
    public int Id1 { get; set; }
    public int Id2 { get; set; }
    public DateTime Date { get; set; }
    public State State { get; set; }
}

public enum State
{
    Undefined,
    Success,
    Failed
}

and your items are stored in an Item collection, you can:

  1. group the items by Id1 and Id2
  2. from each group, select the one item with the latest Date value (using .MaxBy())
    • ( .MaxBy( * ) could alternatively be replaced with .OrderByDescending( * ).First() )
  3. filter the now distinct-by-Id1-and-Id2 item collection to keep only the items that either have State = Failed or are no less than a week old

For an item collection List<Item> items, it could be implemented as follows:

List<Item> result = items
    .GroupBy(item => ( item.Id1, item.Id2 ))
    .Select(gr => gr.MaxBy(item => item.Date))
    .Where(item =>
          item.State == State.Failed ||
          item.Date > DateTime.Now.AddDays(-7))
    .ToList();

Example fiddle here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文