左连接日期,分组结果,在分组结果中显示所有日期,即使为空

时间:2016-03-18 21:02:09

标签: asp.net-mvc linq-to-sql

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

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

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

我目前的成绩:

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列表中所有日期相关联的Person名称,我只是不确定如何做到这一点。日期范围列表中唯一的参数是日期,因此无需加入任何内容。

1 个答案:

答案 0 :(得分:1)

您可以对该人进行GroupBy,然后对于您的范围中的每个日期,您将保留该日期的日期和预定事件(我将其命名为ToDo)。我猜你每个日期可以有多个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: http://stackoverflow.com/questions/3738748/create-an-array-or-list-of-all-dates-between-two-dates
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>
        }
    }
}