C# 当涉及筛选、展平和分组时,理解Linq查询结构存在问题

C# 当涉及筛选、展平和分组时,理解Linq查询结构存在问题,c#,linq,linq-to-entities,ef-core-2.1,C#,Linq,Linq To Entities,Ef Core 2.1,我在尝试使用LinqToEntities从这个数据模型中获取数据时遇到了很多问题 我正在SQL Server数据库上使用EF Core 2.1和Linq 基本上,我需要在每周日历上显示事件,但数据结构相当复杂。 事件可以有多个EventDate(每个日期都是一天,有一个开始和结束时间),并且在每一天,许多不同的联系人有时会在不同的时间与EventDate上的一般联系人在不同的时间进行联系 我需要按一周时间(开始日期、结束日期)过滤它们,偶尔也要按涉及的联系人列表过滤 主要问题是,我需要为每个Ev

我在尝试使用LinqToEntities从这个数据模型中获取数据时遇到了很多问题

我正在SQL Server数据库上使用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或将其与在一个或多个初始查询后在内存中运行的LINQToObject混合使用

我尝试过不同的连接和分组,但我不知道如何使它工作

以下是数据模型:

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; }

}
公共类事件{
公共活动()
{
EventDates=newhashset();
EventDatesContacts=newHashSet();
}
公共int ID{get;set;}
公共字符串名称{get;set;}
…其他数据
公共虚拟ICollection事件日期{get;set;}
公共虚拟ICollection EventDatesContacts{get;set;}
}
公共类事件日期{
公共事件日期()
{
EventDatesContacts=newHashSet();
}
公共int ID{get;set;}
public int EventID{get;set;}
//从到之间的日期部分保持不变。
//只有时间可以改变。
公共日期时间FromDateTime{get;set;}
公共日期时间ToDateTime{get;set;}
//…其他数据
公共虚拟事件事件{get;set;}
公共虚拟ICollection EventDatesContacts{get;set;}
}
公共类EventDatesContact{
公共int ID{get;set;}
public int EventID{get;set;}
public int ContactID{get;set;}
public int EventDateID{get;set;}
//如果不为null,则这些将覆盖EventDate中相应的日期时间
//日期部分在From和To之间保持不变,并且与链接的EventDate相同。
//只有时间可以改变。
public DateTime?OverrideFromTime{get;set;}
公共日期时间?覆盖时间{get;set;}
//…其他数据
公共虚拟联系人联系人{get;set;}
公共虚拟事件日期{get;set;}
公共虚拟事件事件{get;set;}
}

提前感谢您的支持

我不怎么使用EF,但你不需要加入EF。您应该能够只使用导航属性,但您需要分组,因为您正在合并结果中的
EventDate.eventdates联系人。以下是我的尝试:

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()
                }));

我的理解是,如果启用了即时加载,您可能不需要包含。

LinqToSql与EF(Core)中使用的LinqToEntities完全不同(而且非常过时)。可能LinqToSql实际上指的是LinqToEntities,而LinqToEntities指的是LinqToObject。如果你能更正文章中的术语就好了,因为目前它很混乱。除此之外,
eventdatescocontact
中的
事件
看起来多余,很难理解它们之间的关系。它们不应该是事件1吗。。事件日期。。N联系人?你能展示一下你的尝试吗?在我看来,你需要两个连接和两个群组旁路。@IvanStoev是的,对不起,我用错了术语。现在修好了!关于这种关系的真实性,我可以把它去掉。谢谢,我刚刚添加了日期和联系人的筛选功能,因为我需要筛选结果,它正在工作。我的疑问是,检查生成的查询似乎会生成很多查询来获取数据,每个EventDate都会生成一个查询。这是否会在事件数量增长时产生性能问题?是的,根据涉及的数据大小,它可能无法很好地扩展。如果您可以显示生成所需内容的单个SQL查询,我可以使用my尝试转换为更好的LINQ查询,但EF Core还不能转换为EF(这就是为什么使用LINQ转换为SQL或EF的部分原因)。注意,不要对EF Core不公平,如果将某些查询拆分为多个查询,则速度会更快。取决于数据大小、索引、服务器性能等。还有一个问题,在EventDates子查询上添加where筛选器与在末尾将其串联有什么区别吗?实际上,我需要根据传递的参数动态组合查询,在事件、EventDate和EventContacts上添加不同的筛选器。@ilFusta我认为这取决于您的数据库提供程序,我建议使用LINQPad或类似的工具进行测试。