我如何 "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 实体。
我正在尝试确定一种使用 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 实体。