我如何 "expand" 基于值范围的 IQueryable 结果?

How can I "expand" IQueryable results based on a range of values?

我正在尝试确定一种使用 Linq within IQueryable 的方法,以 "expand" 一个实体根据值的范围转换为多个查询结果.具体来说,将结果扩展到开始日期和结束日期之间的每一天,包括在内。

以下是关注的实体(为清楚起见,它们已经精简并删除了注释):

public class Location {
    public int Id { get; set; }
    public string Name { get; set; }
}
public class WorkAssignment {
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public virtual Location Location { get; set; }
    public int LocationId { get; set; }
}

举个例子,假设我们有:

地点:

Id    Name
 1    Habitat
 2    Church

工作分配:

Id   Name         Start         End      LocationId
 1   Jim       29-Apr-2019   3-May-2019      1
 2   Natasha    4-May-2019   7-May-2019      2
 3   Jennifer   5-May-2019   6-May-2019      2

我想使用 Linq 获得以下内容,最好使用流畅的接口方法。在 查询 中执行 "expansion" 很重要(让数据库负责)。完整的数据集和引用的实体是 large,我不希望使用 .ToList()foreach 语句来实现。

WorkerName    Date      LocationId   LocationName
Jim        29-Apr-2019      1          Habitat
Jim        30-Apr-2019      1          Habitat
Jim         1-May-2019      1          Habitat
Jim         2-May-2019      1          Habitat
Jim         3-May-2019      1          Habitat
Natasha     4-May-2019      2          Church
Natasha     5-May-2019      2          Church
Natasha     6-May-2019      2          Church
Natasha     7-May-2019      2          Church
Jennifer    5-May-2019      2          Church
Jennifer    6-May-2019      2          Church

最终目标是获得上述"expansion"以便按位置分组(按位置名称排序)然后按日期分组(按升序排序)然后按名称提供登录sheet 给工人。登录 sheet 按位置分组,然后按日期分组。每个 sheet 将列出特定日期特定地点的工作人员。

我已经弄清楚了分组查询(感谢 Jon Skeet 和他所有出色的 SO 答案)。如果甚至可以在 IQueryable.

范围内完成,我只需要上述扩展方面的帮助

一种解决方案是结合使用日历或日期维度 table (https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/) 和视图来表示您的日期范围,return 表示每个日期的实体在范围内。

例如:

public class WorkAssignment {
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public virtual Location Location { get; set; }
    public int LocationId { get; set; }
}

[Table("vwWorkAssignmentByDate")]
public class WorkAssignmentDate 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public virtual Location Location { get; set; }
    public int LocationId { get; set; }
    public DateTime Date { get; set; }
}

请注意,WorkAssignmentDate 不会扩展 WorkAssignment。这样做的原因是,如果您扩展它,当直接查询 WorkAssignment 时,EF 将尝试对视图进行 NOT IN,这既会降低性能,又会在尝试加载单行时导致问题。 (可能有某种形式的映射可以避免这种行为)您可以将 Id 设置为 view-based 实体的 PK 以使 EF 满意,但它不会是唯一的行标识符。 (所以没有更新!这不是问题,因为无论如何这是从视图中获取的)

其中 vwWorkAssignment 是将 WorkAssignment 加入 DateDimension 的视图 table:

SELECT wa.*, dd.Date
FROM dbo.WorkAssignment wa 
INNER JOIN dbo.DateDimension dd 
  ON dd.Date >= wa.StartDate AND dd.Date <= wa.EndDate

WorkAssignmentDate 实体需要被视为 read-only 实体。要更新工作分配,您将按 ID 加载和使用 WorkAssignment 实体。