Linq - 从空查询结果中提取值

时间:2009-09-11 17:12:37

标签: linq-to-sql lambda

我有一个linq查询,需要从一行中提取日期列。表达式目前看起来像这样

myObject.OrderByDescending(s=> s.MyDate).Where(s => s.CRAStatus.Description == "CheckedOut").FirstOrDefault().MyDate)

问题是如果没有“CheckedOut”行,查询将返回null并尝试获取“MyDate”将引发异常。我们有一些冗长的解决方案,例如:

.ForMember(dest => dest.CheckOutDate, opt => opt.MapFrom(src => {
    var temp = src.CRAStatusChangeEvents.OrderByDescending(s=> s.MyDate).Where(s => s.CRAStatus.Description == "CheckedOut").FirstOrDefault();
    return temp == null ? temp.MyDate : null;
}));

但要找到更简洁的东西会更好。任何想法?

4 个答案:

答案 0 :(得分:4)

为什么不

myObject.OrderByDescending(s=> s.MyDate)
        .Where(s => s.CRAStatus.Description == "CheckedOut")
        .Select(s => s.MyDate as DateTime?)
        .FirstOrDefault();

myObject.Where(s => s.CRAStatus.Description == "CheckedOut")
        .Max(s => s.MyDate as DateTime?);

答案 1 :(得分:3)

一个选项是将default if empty设置为“空”实例(想想string.Empty - 它是一个表示空结果的已知实例):

var date = (myObject
    .OrderByDescending(s=> s.MyDate)
    .Where(s => s.CRAStatus.Description == "CheckedOut")
    .DefaultIfEmpty(MyObject.Empty)
    .FirstOrDefault()).MyDate;

以下是一个显示其工作原理的摘录:

var strings = new string[]{"one", "two"};
var length = 
    (strings.Where(s=>s.Length > 5)
    .DefaultIfEmpty(string.Empty)
    .FirstOrDefault()).Length;

运行它,长度为0.删除DefaultIfEmpty行,你得到一个NRE。

答案 2 :(得分:1)

var checkedOut = myObject.Where(s => s.CRAStatus.Description == "CheckedOut");
if (checkedOut.Count() > 0) {
   var result = checkedOut.Max(s=> s.MyDate).MyDate;
}

答案 3 :(得分:1)

扩展方法怎么样?

static class MyObjectEnumerableExtensions
{
    public static TMember GetMemberOfFirstOrDefault<TMember>(this IEnumerable<MyObject> items, Func<MyObject, TMember> getMember)
    {
        MyObject first = items.FirstOrDefault();
        if (first != null)
        {
            return getMember(first);
        }
        else
        {
            return default(TMember);
        }
    }
}

样本用法:

List<MyObject> objects = new List<MyObject>();
objects.Add(new MyObject { MyDate = DateTime.MinValue });

var filteredObjects = from s in objects where s.MyDate > DateTime.MinValue select s;

DateTime date = filteredObjects.GetMemberOfFirstOrDefault(s => s.MyDate);

Console.WriteLine(date);