【问题标题】:How can I "expand" IQueryable results based on a range of values?如何根据一系列值“扩展” IQueryable 结果?
【发布时间】:2019-09-26 09:55:56
【问题描述】:

我正在尝试确定一种使用 Linq IQueryable 中的方法,以根据一系列值将实体“扩展”为多个查询结果。具体来说,将结果按开始日期和结束日期之间的每一天(包括日期)展开。

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

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 获得以下内容,最好使用流畅的接口方法。在查询中执行“扩展”很重要(让数据库负责)。完整的数据集和引用的实体很大,我不希望使用.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

最终目标是获得上述“扩展”,以便按位置分组(按位置名称排序)然后按日期分组(按升序排列),然后按名称分组,为工人提供签到表。登录表按位置分组,然后按日期分组。每张表都会列出特定日期特定地点的工人。

我已经弄清楚了分组查询(感谢 Jon Skeet 和他所有很棒的 SO 答案)。如果可以在 IQueryable 内进行,我只需要上述扩展方面的帮助。

【问题讨论】:

    标签: c# entity-framework linq iqueryable fluent


    【解决方案1】:

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

    例如:

    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 将尝试对视图不输入,这既是性能接收器,也可能在尝试加载单行时导致问题。 (可能有某种形式的映射可以避免这种行为)您可以将 Id 设置为基于视图的实体的 PK 以保持 EF 满意,但它不会是唯一的行标识符。 (所以没有更新!不是问题,因为无论如何这都是从视图中获取的)

    其中 vwWorkAssignment 是将 WorkAssignment 连接到 DateDimension 表的视图:

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

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

    【讨论】:

    • 谢谢。我希望不使用日期维度表,但我没有在我的问题中说明这一点。由于这是 a 可行的解决方案(也是唯一建议的解决方案),因此我将其标记为答案。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2020-12-16
    • 2014-04-06
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多