开发者

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜