LINQ: display results from empty lists
I've created two entities (simplified) in C#:
class Log {
entries = new List<Entry>();
DateTime Date { get; set; }
IList<Entry> entries { get; set; }
}
class Entry {
DateTime ClockIn { get; set; }
DateTime ClockOut { get; set; }
}
I am using the following code to initialize the objects:
Log log1 = new Log() {
Date = new DateTime(2010, 1, 1),
};
log1.Entries.Add(new Entry() {
ClockIn = new DateTime(0001, 1, 1, 9, 0, 0)开发者_如何学C,
ClockOut = new DateTime(0001, 1, 1, 12, 0, 0)
});
Log log2 = new Log()
{
Date = new DateTime(2010, 2, 1),
};
The method below is used to get the date logs:
var query =
from l in DB.GetLogs()
from e in l.Entries
orderby l.Date ascending
select new
{
Date = l.Date,
ClockIn = e.ClockIn,
ClockOut = e.ClockOut,
};
The result of the above LINQ query is:
/*
Date | Clock In | Clock Out
01/01/2010 | 09:00 | 12:00
*/
My question is, what is the best way to rewrite the LINQ query above to include the results from the second object I created (Log2), since it has an empty list. In the other words, I would like to display all dates even if they don't have time values.
The expected result would be:
/*
Date | Clock In | Clock Out
01/01/2010 | 09:00 | 12:00
02/01/2010 | |
*/
Try this:
var query =
from l in DB.GetLogs()
from e in l.Entries.DefaultIfEmpty()
orderby l.Date ascending
select new
{
Date = l.Date,
ClockIn = e == null ? null : e.ClockIn,
ClockOut = e == null ? null : e.ClockOut,
};
See the docs for DefaultIfEmpty
for more information on it.
EDIT: You might want to just change it to perform the final part in memory:
var dbQuery =
from l in DB.GetLogs()
from e in l.Entries.DefaultIfEmpty()
orderby l.Date ascending
select new { Date = l.Date, Entry = e };
var query = dbQuery.AsEnumerable()
.Select(x => new {
Date = x.Date,
ClockIn = x.Entry == null ? null : x.Entry.CLockIn,
ClockOut = x.Entry == null ? null : x.Entry.CLockOut
});
This is building on top of Jon's solution. Using it I get the following error:
Cannot assign to anonymous type property
I have updated Jon's example to the following and it appears to give the desired result:
var logs = new []{log1,log2};
var query =
from l in logs.DefaultIfEmpty()
from e in l.entries.DefaultIfEmpty()
orderby l.Date ascending
select new
{
Date = l.Date,
ClockIn = e == null ? (DateTime?)null : e.ClockIn,
ClockOut = e == null ? (DateTime?)null : e.ClockOut,
};
query.Dump();
Andrew
P.S. the .Dump() is due to me using LINQ Pad.
You should have a look at the LINQ Union Operator.
http://srtsolutions.com/public/blog/251070
精彩评论