Left Join on Date,分组结果,在分组结果中显示所有日期,即使为空

Left Join on Date, Grouping Results, Display all Dates, even if empty, in grouped result

我使用 MVC 5/EF 6。我一直在尝试创建一个为多人显示日历的视图。

我已经有了按人分组的视图,并且显示了搜索范围内所有日期的列表。但是,如果该人没有为该日期安排任何事情,则该日期不会列在该人的下方。

现在,没有人安排任何事情的空日期被归入一个 "empty" 人组。

我目前的成绩:

Person: 
-------------------------------
04/01/16 (blank)
04/02/16 (blank)
04/03/16 (blank)

Person: Jane
-------------------------------
04/04/2016: To Do Item
04/05/2016: To Do Item

Person: John
-------------------------------
04/04/2016: To Do Item
04/05/2016: To Do Item

我怎样才能得到这个结果?

Person: Jane
-------------------------------
04/01/16 (blank)
04/02/16 (blank)
04/03/16 (blank)
04/04/2016: To Do Item
04/05/2016: To Do Item

Person: John
-------------------------------
04/01/16 (blank)
04/02/16 (blank)
04/03/16 (blank)
04/04/2016: To Do Item
04/05/2016: To Do Item

查询返回查看

var activecal = db.Calendar.Where(x => (x.CalDate >= startdate && x.CalDate <= enddate).ToList();


// merge calendar with date range in search selected 

var calendar = (from d in dateRange //dateRange = date range search
                    join c in activecal.ToList() on d equals c.CalDate into joinedResult
                    from r in joinedResult.DefaultIfEmpty()
                    select new CalVM
                    {
                      FullName = r == null ? null : r.FullName,
                      CalLocation = r == null ? null : r.CalLocation,
                      calDay = d.Date,                
                    }).ToList();

查看

@{
        foreach (var group in Model.GroupBy(a => a.FullName))
        {
            <h3>Person: @group.Key</h3>
            <div class="table-responsive">
                <table class="table table-hover small">
                    <tr>
                        <th>
                            Cal Day
                        </th>
                        <th>
                            Location
                        </th>
                    </tr>
                    @foreach (var i in group)
                    {
                        <tr>
                            <td>
                                @Html.DisplayFor(modelItem => i.calDay) 
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => i.CalLocation)
                            </td>                         
                        </tr>
                    }
                </table>
            </div>
        }
    }

我知道我必须以某种方式获取与 dateRange 列表中的所有日期相关联的人名,我只是不确定该怎么做。日期范围列表中的唯一参数是日期,因此没有任何可加入的内容。

您可以将此人分组,然后对于您范围内的每个日期,您将保留该日期的日期和预定事件(我将其命名为 ToDo)。而且我猜你每个日期可以有多个待办事项。

示例:

var dateRange = GetDateRange(new DateTime(2016, 1, 1), new DateTime(2016, 1, 5)).ToList();

var todos = new List<ToDo>
{
    new ToDo { Date = new DateTime(2016,1,3), Person = "John", What = "Do that"},
    new ToDo { Date = new DateTime(2016,1,4), Person = "John", What = "Do this"},
    new ToDo { Date = new DateTime(2016,1,4), Person = "John", What = "Do nothing"},

    new ToDo { Date = new DateTime(2016,1,2), Person = "Jane",What = "Do something"},
    new ToDo { Date = new DateTime(2016,1,3), Person = "Jane", What = "Do whatever"}
};

var personToDos = todos.GroupBy(x => x.Person)
    .ToDictionary(key => key.Key, value => dateRange.Select(date => new ToDosPerDate
    {
        Date = date,
        ToDos = value.Where(a => a.Date == date)
    }));

foreach (var item in personToDos)
{
    Console.WriteLine(item.Key);
    Console.WriteLine("---------------");
    foreach (var model in item.Value)
    {
        Console.Write(model.Date + " ");
        Console.WriteLine(string.Join(", ", model.ToDos));
    }
    Console.WriteLine();
}

还有其他东西:

public class ToDo
{
    public DateTime Date { get; set; }

    public string Person { get; set; }

    public string What { get; set; }

    public override string ToString()
    {
        return What;
    }
}

public class ToDosPerDate
{
    public DateTime Date { get; set; }

    public IEnumerable<ToDo> ToDos { get; set; }
}

// From: 
public static IEnumerable<DateTime> GetDateRange(DateTime startDate, DateTime endDate)
{
    if (endDate < startDate)
        throw new ArgumentException("endDate must be greater than or equal to startDate");

    while (startDate <= endDate)
    {
        yield return startDate;
        startDate = startDate.AddDays(1);
    }
} 

以上代码的输出为:

John
---------------
2016-01-01 12:00:00 AM
2016-01-02 12:00:00 AM
2016-01-03 12:00:00 AM Do that
2016-01-04 12:00:00 AM Do this, Do nothing
2016-01-05 12:00:00 AM

Jane
---------------
2016-01-01 12:00:00 AM
2016-01-02 12:00:00 AM Do something
2016-01-03 12:00:00 AM Do whatever
2016-01-04 12:00:00 AM
2016-01-05 12:00:00 AM

在 MVC Razor 视图中输出 personToDos 的示例:

@model Dictionary<string, IEnumerable<ToDosPerDate>>
...
@foreach (var person in Model)
{
    <h3>@person.Key</h3>

    foreach (var d in person.Value)
    {
        <div>Date: @d.Date</div>

        foreach (var todo in d.ToDos)
        {
            <div>@todo.What</div>
        }
    }
}