涉及过滤、展平和分组时理解 Linq 查询结构的问题
Problem understanding Linq query structure when involves filtering, flattening and grouping
我在尝试使用 LinqToEntities 从此数据模型获取数据时遇到了很多问题。
我在 SQL 服务器数据库上使用 EF Core 2.1 和 Linq。
基本上我需要在每周日历上显示事件,但数据结构相当复杂。
事件可以有多个 EventDate(每个日期都是一天,有开始和结束时间)并且每天都有许多不同的联系人参与,有时与 EventDate 上的通用时间不同。
我需要按周(开始日期、结束日期)过滤它们,有时还需要按所涉及的联系人列表进行过滤。
主要问题是我需要为每个 EventDate 提取一个不同对象的列表(按要求过滤),但其中包含所有覆盖分组以及每个覆盖组的联系人列表,就像这个示例结构:
EventID,
EventName,
//...Other Data from Events
FromDateTime, //Taken from the EventDate Table
ToDateTime, //Taken from the EventDate Table
//...Other Data from EventDates
Overrides:[
//Taken from the EventDateContact Table
{
OverrideFromHour,
OverrideToHour
Contacts [contactid, contactid, ...]
},
{
OverrideFromHour,
OverrideToHour
Contacts [contactid, contactid, ...]
}
]
我在理解非常复杂的查询中的 LinqToEntities 时仍然遇到问题。
在非 EF/Linq 应用程序中,我会在表之间进行连接,然后根据需要手动对结果分组进行迭代,但我想知道是否有办法直接使用 LinqToEntities 或混合执行此操作它与 LinqToObjects 在一次或一次不同的初始查询后在内存中唤醒。
我已经尝试过不同的连接和分组,但我不知道它是如何工作的!
这是数据模型:
public class Event {
public Event()
{
EventDates = new HashSet<EventDate>();
EventDatesContacts = new HashSet<EventDatesContact>();
}
public int ID { get; set; }
public string Name { get; set; }
...other data
public virtual ICollection<EventDate> EventDates { get; set; }
public virtual ICollection<EventDatesContact> EventDatesContacts { get; set; }
}
public class EventDate {
public EventDate()
{
EventDatesContacts = new HashSet<EventDatesContact>();
}
public int ID { get; set; }
public int EventID { get; set; }
//The Date part remain the same between From and To.
//Only the Hour can change.
public DateTime FromDateTime { get; set; }
public DateTime ToDateTime { get; set; }
//...other data
public virtual Event Event { get; set; }
public virtual ICollection<EventDatesContact> EventDatesContacts { get; set; }
}
public class EventDatesContact {
public int ID { get; set; }
public int EventID { get; set; }
public int ContactID { get; set; }
public int EventDateID { get; set; }
//If not null these overrides the corresponding DateTime in the EventDate
//The Date part remain the same between From and To and also the same as the linked EventDate.
//Only the Hour can change.
public DateTime? OverrideFromTime { get; set; }
public DateTime? OverrideToTime { get; set; }
//...other data
public virtual Contact Contact { get; set; }
public virtual EventDate EventDate { get; set; }
public virtual Event Event { get; set; }
}
提前感谢您的支持!
我用 EF 不多,但你应该不需要加入 EF。您应该能够只使用导航属性,但您需要分组,因为您正在合并结果中的 EventDate.EventDatesContacts
。这是我的尝试:
var results = db.Events
.Include(e => e.EventDates).ThenInclude(ed => ed.EventDatesContacts)
.SelectMany(e => e.EventDates.Select(ed => new Result {
EventID = e.ID,
EventName = e.Name,
FromDateTime = ed.FromDateTime,
ToDateTime = ed.ToDateTime,
Overrides = ed.EventDatesContacts.GroupBy(edc => new {
FromTime = edc.OverrideFromTime == null ? ed.FromDateTime : edc.OverrideFromTime.Value,
ToTime = edc.OverrideToTime == null ? ed.ToDateTime : edc.OverrideToTime.Value
},
edc => edc.ContactID
)
.Select(edcg => new EventOverride {
OverrideFromHour = edcg.Key.FromTime,
OverrideToHour = edcg.Key.ToTime,
ContactIDs = edcg.ToList()
})
.ToList()
}));
我的理解是,如果您启用了预先加载,则可能不需要 Include
。
我在尝试使用 LinqToEntities 从此数据模型获取数据时遇到了很多问题。
我在 SQL 服务器数据库上使用 EF Core 2.1 和 Linq。
基本上我需要在每周日历上显示事件,但数据结构相当复杂。 事件可以有多个 EventDate(每个日期都是一天,有开始和结束时间)并且每天都有许多不同的联系人参与,有时与 EventDate 上的通用时间不同。
我需要按周(开始日期、结束日期)过滤它们,有时还需要按所涉及的联系人列表进行过滤。
主要问题是我需要为每个 EventDate 提取一个不同对象的列表(按要求过滤),但其中包含所有覆盖分组以及每个覆盖组的联系人列表,就像这个示例结构:
EventID,
EventName,
//...Other Data from Events
FromDateTime, //Taken from the EventDate Table
ToDateTime, //Taken from the EventDate Table
//...Other Data from EventDates
Overrides:[
//Taken from the EventDateContact Table
{
OverrideFromHour,
OverrideToHour
Contacts [contactid, contactid, ...]
},
{
OverrideFromHour,
OverrideToHour
Contacts [contactid, contactid, ...]
}
]
我在理解非常复杂的查询中的 LinqToEntities 时仍然遇到问题。
在非 EF/Linq 应用程序中,我会在表之间进行连接,然后根据需要手动对结果分组进行迭代,但我想知道是否有办法直接使用 LinqToEntities 或混合执行此操作它与 LinqToObjects 在一次或一次不同的初始查询后在内存中唤醒。
我已经尝试过不同的连接和分组,但我不知道它是如何工作的!
这是数据模型:
public class Event {
public Event()
{
EventDates = new HashSet<EventDate>();
EventDatesContacts = new HashSet<EventDatesContact>();
}
public int ID { get; set; }
public string Name { get; set; }
...other data
public virtual ICollection<EventDate> EventDates { get; set; }
public virtual ICollection<EventDatesContact> EventDatesContacts { get; set; }
}
public class EventDate {
public EventDate()
{
EventDatesContacts = new HashSet<EventDatesContact>();
}
public int ID { get; set; }
public int EventID { get; set; }
//The Date part remain the same between From and To.
//Only the Hour can change.
public DateTime FromDateTime { get; set; }
public DateTime ToDateTime { get; set; }
//...other data
public virtual Event Event { get; set; }
public virtual ICollection<EventDatesContact> EventDatesContacts { get; set; }
}
public class EventDatesContact {
public int ID { get; set; }
public int EventID { get; set; }
public int ContactID { get; set; }
public int EventDateID { get; set; }
//If not null these overrides the corresponding DateTime in the EventDate
//The Date part remain the same between From and To and also the same as the linked EventDate.
//Only the Hour can change.
public DateTime? OverrideFromTime { get; set; }
public DateTime? OverrideToTime { get; set; }
//...other data
public virtual Contact Contact { get; set; }
public virtual EventDate EventDate { get; set; }
public virtual Event Event { get; set; }
}
提前感谢您的支持!
我用 EF 不多,但你应该不需要加入 EF。您应该能够只使用导航属性,但您需要分组,因为您正在合并结果中的 EventDate.EventDatesContacts
。这是我的尝试:
var results = db.Events
.Include(e => e.EventDates).ThenInclude(ed => ed.EventDatesContacts)
.SelectMany(e => e.EventDates.Select(ed => new Result {
EventID = e.ID,
EventName = e.Name,
FromDateTime = ed.FromDateTime,
ToDateTime = ed.ToDateTime,
Overrides = ed.EventDatesContacts.GroupBy(edc => new {
FromTime = edc.OverrideFromTime == null ? ed.FromDateTime : edc.OverrideFromTime.Value,
ToTime = edc.OverrideToTime == null ? ed.ToDateTime : edc.OverrideToTime.Value
},
edc => edc.ContactID
)
.Select(edcg => new EventOverride {
OverrideFromHour = edcg.Key.FromTime,
OverrideToHour = edcg.Key.ToTime,
ContactIDs = edcg.ToList()
})
.ToList()
}));
我的理解是,如果您启用了预先加载,则可能不需要 Include
。