Get default value type (DateTime) in Linq to Sql query with empty results

前端 未结 4 948
情歌与酒
情歌与酒 2021-01-27 03:07

I am having a problem returning a default DateTime value from a complex Linq-to-Sql query.

Hopefully the following simplified example shows the

相关标签:
4条回答
  • 2021-01-27 03:47
    users.Select(u =>
      new MyDomainObject(
         u.Id,
         u.Transactions
            .Where(t => false) // empty results set
            .Select(t => t.TransactionTime)
            .Any() ?
         u.Transactions
            .Where(t => false) // empty results set
            .Select(t => t.TransactionTime) // TransactionTime is DATETIME NOT NULL
            .OrderByDescending(x => x)
            .FirstOrDefault() : // I want DateTime.MinValue (or SqlDateTime.MinValue)
         DateTime.MinValue
      )
    );
    

    This will supply DateTime.MinValue if there are no transactions available for that object.

    0 讨论(0)
  • This will supply DateTime.MinValue if there are no transactions available for that object, example:

    users.Select(u =>
      new MyDomainObject(
         u.Id,
         u.Transactions
            .Where(t => false) // empty results set
            .Select(t => t.TransactionTime)
            .Any() ?
         u.Transactions
            .Where(t => false) // empty results set
            .Select(t => t.TransactionTime) // TransactionTime is DATETIME NOT NULL
            .OrderByDescending(x => x)
            .FirstOrDefault() : // I want DateTime.MinValue (or SqlDateTime.MinValue)
         DateTime.MinValue
      )
    );
    
    0 讨论(0)
  • 2021-01-27 04:02

    The error implies that t.TransactionTime is nullable (i.e. DateTime?). Even if the field can't be null in the database if the property is nullable and the query returns no rows FirstOrDefault() will return null as this is the default value of t.TransactionTime

    EDIT

    further to your comments, that is very strange: the below code outputs True

    List<DateTime> dates = new List<DateTime>();
    DateTime date = dates.FirstOrDefault();
    Console.WriteLine(date == DateTime.MinValue);
    

    And i would expect your code to do the same.

    0 讨论(0)
  • 2021-01-27 04:04

    I'd be very tempted to actually use a nullable DateTime for this. For example, from your "Car" sample:

    var test = _dataContext.GetTable<Car>
                           .Select(c => 
                               c.MechanicVisits
                                .Select(m => m.ServiceRecord)
                                .Select(s => (DateTime?) s.ServiceDate)
                                .OrderByDescending(d => d)
                                .FirstOrDefault()
                           ).ToList();
    

    That way I suspect you'll end up with it working and giving you null DateTime? values. You could always transform that later if you wanted:

    var test = _dataContext.GetTable<Car>
                           .Select(c => 
                               c.MechanicVisits
                                .Select(m => m.ServiceRecord)
                                .Select(s => (DateTime?) s.ServiceDate)
                                .OrderByDescending(d => d)
                                .FirstOrDefault()
                           ).AsEnumerable()
                            .Select(dt => dt ?? DateTime.MinValue)
                            .ToList();
    

    Original answer (doesn't work)

    Hmm. I won't claim to fully understand the reasons for this, but here's a potential workaround:

    users.Select(u =>
      new MyDomainObject(
         u.Id,
         u.Transactions
            .Where(t => false)
            .Select(t => t.TransactionTime)
            .OrderByDescending(x => x)
            .DefaultIfEmpty(DateTime.MinValue)
            .First()
      )
    ); 
    

    In other words, if the result set is empty, use the specified default - and then take the first result of the now-definitely-not-empty sequence.

    0 讨论(0)
提交回复
热议问题