涉及过滤,展平和分组时,对Linq查询结构的理解有问题

时间:2018-12-04 20:12:29

标签: c# linq linq-to-entities ef-core-2.1

尝试使用LinqToEntities从此数据模型中获取数据时,我遇到很多问题。

我正在使用SQL Server数据库上的EF Core 2.1和Linq。

基本上,我需要在每周日历上显示事件,但是数据结构非常复杂。 事件可以具有多个EventDate(每个日期都是一天,带有开始和结束时间),而且每天有许多不同的Contact参加会议的时间有时不同于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; }

}

在此先感谢您的支持!

1 个答案:

答案 0 :(得分:1)

我使用EF的程度不高,但是您不需要加入EF。您应该只可以使用Navigation属性,但是由于要在结果中合并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