簡體   English   中英

如何將這個linq縮短為sql查詢?

[英]How can I shorten this linq to sql query?

我正在制作一個日歷,為了讓自己更容易,我分手了幾個星期的約會。

例如1月1日到1月31日跨越6周(我的日歷總是42個單元格 - 6乘7)。 所以我基本上會在我的數據庫中存儲6行。

但是我確實需要把所有這些行重新組合成一行。 例如,如果我想以Ical格式導出我的日歷。

我的數據庫中有一個名為bindingClassName的字段,所有這些行都獲得了與該組任務相同的unquie id,因此我可以輕松地獲得所有周。

// get all of the task rows by binding class name.
            var found = plannerDb.Calendars.Where(u => u.UserId == userId && u.BindingClassName == bindingClassName)
                .GroupBy(u => u.BindingClassName);



            List<Calendar> allAppoingments = new List<Calendar>();

            // go through each of the results and add it to a list of calendars
            foreach (var group in found)
            {

                foreach (var row in group)
                {

                    Calendar appointment = new Calendar();
                    appointment.AppointmentId = row.AppointmentId;
                    appointment.AllDay = row.AllDay;
                    appointment.BindingClassName = row.BindingClassName;
                    appointment.Description = row.Description;
                    appointment.EndDate = row.EndDate;
                    appointment.StartDate = row.StartDate;
                    appointment.Title = row.Title;
                    appointment.Where = row.Where;
                    appointment.UserId = row.UserId;

                    allAppoingments.Add(appointment);
                }
            }
            // order 
           var test = allAppoingments.OrderBy(u => u.StartDate);

           var firstAppointment = test.First();
           var LastAppointment = test.Last();

           Calendar newAppointment = new Calendar();
           newAppointment.UserId = firstAppointment.UserId;
           newAppointment.Description = firstAppointment.Description;
           newAppointment.AllDay = firstAppointment.AllDay;
           newAppointment.StartDate = firstAppointment.StartDate;
           newAppointment.Title = firstAppointment.Title;
           newAppointment.Where = firstAppointment.Where;
           newAppointment.BindingClassName = firstAppointment.BindingClassName;
           newAppointment.EndDate = LastAppointment.EndDate;

            return newAppointment;

所以基本上這個大blob找到具有相同綁定名稱的所有約會。 然后我瀏覽每一個並將其變成一個Calendar對象,然后一旦完成,我得到第一個和最后一個記錄來獲取startDate和endDate。

所以我對linq並不擅長,但我不確定我是否可以在groupBy之后添加一些東西來做我想做的事情。

編輯。

一旦我從用戶那里得到所有約會,我正在嘗試將所有約會組合在一起。

所以到目前為止我有這個

我試過這樣的事。

    var allApointments = calendar.GetAllAppointments(userId);
    var group = allApointments.GroupBy(u => u.BindingClassName).Select(u => new Calendar()).ToList

我希望它會自動填充每個組,但事實並非如此。 所以我不確定是否不再需要groupby。

編輯@ admin

嗨,謝謝你解釋排序和分組。 你怎么解釋它雖然似乎任何人都會工作。

就像你獲得第一個和最后一個日期的代碼一樣,它可以很好地完成我想做的事情。

我認為分組可能有效,因為最后雖然我只想要有一行具有第一個記錄的開始日期和最后一個記錄的結束日期,但所有其他信息都是相同的。

所以我不知道是否更難寫這個或者更像是我說你的查詢做了我想要的。

但是,該查詢在單個基礎上使用。 就像我只在用戶點擊我的日歷上查看該約會時才使用該查詢。 通過點擊約會我獲得有關該約會的所有信息,如果該任務跨越多天,我需要查看該信息,並確定約會何時開始以及何時結束。

現在我需要另一個查詢,我認為如果我能將它們組合起來會更好,因為我從你的解釋中理解它會產生一行。 我認為這是因為我想從該用戶導出表中的所有記錄。

因此,如果我通過綁定名稱將它們命令為一個繼續塊,我仍然需要一些遍歷所有記錄的循環並獲取第一個和開始日期。 因此,如果我可以一次性對其進行分組,並且最終結果將是每組綁定名稱的一個記錄,並且它將具有第一個開始日期,並且來自第一個和最后一個記錄的最后結束日期將更好。

如果您實際上沒有使用該組,為什么要對約會進行分組? 看起來你只是單獨使用它們。 在任何情況下,您已經在Where子句中為BindingClassName的單個值過濾了行,因此您最終只會得到1(或0)個組。

您可以將這一系列的foreach循環重寫為SelectToList()如下所示:

var allAppointments = 
    plannerDb.Calendars.Where(
    row => row.UserId == userId && 
           row.BindingClassName == bindingClassName).OrderBy(
    row => row.StartDate).Select(
    row => new Calendar()
    {
        AppointmentId = row.AppointmentId,
        AllDay = row.AllDay,
        BindingClassName = row.BindingClassName,
        Description = row.Description,
        EndDate = row.EndDate,
        StartDate = row.StartDate,
        Title = row.Title,
        Where = row.Where,
        UserId = row.UserId
    }).ToList();

這將按照您想要的順序返回完整列表。 但是,我很好奇你為什么要檢索整個列表, 看起來你只對第一個和最后一個約會感興趣。 你可以這樣做:

var baseQuery = 
        plannerDb.Calendars.Where(
        row => row.UserId == userId && 
               row.BindingClassName == bindingClassName);

var first = baseQuery.OrderBy(row => row.StartDate).First();
var last = baseQuery.OrderByDescending(row => row.StartDate).Select(
           row => row.EndDate).First();

return new Calendar()
{
    AppointmentId = first.AppointmentId,
    AllDay = first.AllDay,
    BindingClassName = first.BindingClassName,
    Description = first.Description,
    EndDate = last,
    StartDate = first.StartDate,
    Title = first.Title,
    Where = first.Where,
    UserId = first.UserId
});

這應該產生與你現在相同的輸出。 但是,如果這正是你想要的,我會質疑。 假設您有兩個約會:

  • 預約1從1月5日開始,到1月10日結束
  • 預約2從1月6日開始,到1月7日結束

使用此(和您的)邏輯,您將得到結束日期為1月7日,因為約會2具有較大的開始日期,但約會1實際上稍后結束。 我建議將第二個查詢更改為:

var last = baseQuery.OrderByDescending(row => row.EndDate).Select(
           row => row.EndDate).First();

這將為您提供最大的結束日期 ,我認為這是您實際所追求的目標。

編輯

我認為你正在制造( 非常常見的 )將分組與分類混淆的錯誤。 當你說你想“通過綁定名稱對約會進行分組”時,聽起來你想要一個完整,完整的約會列表,並且你希望這些約會的排列方式與所有具有特定綁定名稱的約會形成一個連續的塊。 如果是這種情況,您希望按綁定名稱對列表進行排序,而不是對它們進行分組。 分組采用整個列表並為每個分組子句生成一行,並允許您對其余列執行聚合功能。 例如,假設我將約束分組在綁定名稱上。 這意味着我的結果集每個綁定名稱將包含一行 ,然后我可以執行諸如查找最大開始日期或結束日期之類的事情; 更正式地說,您可以指定聚合操作,這些操作采用一組數據(即開始日期列表)並返回單個數據(即最大開始日期)。

除非我誤解,否則聽起來你仍然想要檢索所有單獨的任務,你只需要通過綁定名稱來安排它們。 如果是這種情況,只需要OrderBy(row => row.BindingName)就可以了。 此外,您可能希望避免使用“組”這個詞,因為人們會認為您的意思是我上面描述的那種分組。

就像沒有關於linq的側面一樣,你看過AutoMapper嗎? 我目前正在使用它來填充來自linq的數據對象,我發現它對於擺脫你剛剛映射到dtos的大部分代碼非常有用。 它不會使代碼的查詢部分更短,但會減少:

return new Calendar()
{
    AppointmentId = first.AppointmentId,
    AllDay = first.AllDay,
    BindingClassName = first.BindingClassName,
    Description = first.Description,
    EndDate = last,
    StartDate = first.StartDate,
    Title = first.Title,
    Where = first.Where,
    UserId = first.UserId
});

至:

return Mapper.Map(first,new Calendar{EndDate = last});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM