LINQ - 匹配值,如果没有,return NULL 元素

LINQ - Match value, if not, return NULL element

我有一个给定的日期,我想获取 table 上大于给定日期的元素,但如果找不到,我想 return 具有NULL日期。

例如:

Table:

如果给定的日期是,例如,2019-10-20,我想 return ID 为 3 的元素。

如果给定的日期是,例如,2019-11-20,我想 return ID 为 4 的元素。

我试过这样做:

var parameter = _db.Parameter
.OrderBy(x => x.EndDate)
.First(givenDate < x.EndDate) || x.EndDate == null);

但它总是 return 最后一个元素。我需要做什么?

你可以试试这个:

var query = _db.Parameter
            .OrderBy(x => x.EndDate)
            .ToList();

var parameter = query.FirstOrDefault(x => givenDate < x.EndDate);

if ( parameter == null )
  parameter = query.FirstOrDefault(x => x.EndDate == null);

if ( parameter == null )
  ...
else
  ...

我们在日期上创建一个初始排序查询,用一个列表来评估查询。

接下来我们检查第一个 givenDate 是否匹配所需的结果。

否则我们尝试获取第一个空行。

那你就可以办理最后的案子了。

为避免对查询进行两次解析,您可以使用:

TheTypeOfParameter parameterFound = null;
TheTypeOfParameter parameterHavingDateNotNull = null;
TheTypeOfParameter parameterHavingDateNull = null;

bool foundDateNull = false;
bool foundDateNotNull = false;

foreach ( var item in query )
{
  if ( !foundDateNull && item.EndDate == null )
  {
    parameterHavingDateNull = item;
    foundDateNull = true;
  }
  else
  if ( !foundDateNotNull && item.EndDate > givenDate )
    foundDateNotNull = true;
  if ( !foundDateNotNull )
    parameterHavingDateNotNull = item;
  if ( foundDateNotNull || foundDateNull )
    break;
}

parameterFound = parameterHavingDateNotNull != null
               ? parameterHavingDateNotNull
               : parameterHavingDateNull;

因为我不能测试和调试,所以我希望这个循环能工作...

如评论中所述,NULL将在排序后排在第一位。 如果您尝试以下操作会怎样:

var parameter = _db.Parameter
    .Where(x => (x.EndDate > givenDate) || (x.EndDate == null))
    .OrderBy(x => x.EndDate)
    .Last();

仅选择较早的日期后,选择最新的日期。如果列表中只有一个元素(NULL 元素),则选择该元素。

我会通过不使用 LINQ 来优化代码:

var parameter = _db.Parameter[0]; // you may need to handle that there's at least 1 item.
for (int i = 1; i < _db.Parameter.Count; i++)
{
    var param = _db.Parameter[i];
    if (param.EndDate > givenDate)
    { // param is good
        if (parameter.EndDate == null || parameter.EndDate > param.EndDate)
            parameter = param; // replace parameter with param
    }
    else if (parameter.EndDate != null && parameter.EndDate < givenDate)
    { // parameter precedes given date, replace it!
        parameter = param;
    }
}

与目前提供的其他解决方案不同,这将只遍历您的列表一次。

如果您必须使用 LINQ 并希望迭代一次,也许您可​​以使用下面的方法,但它 return 是动态的,因此您需要将其转换回一个Parameter。它的工作原理是将 NULL 替换为 DateTime.MaxValue,这样当您执行 OrderBy 时,NULL 的条目将排在底部。

var param = _db.Parameter
    .Select(x => new
    {
        ID = x.ID,
        EndDate = (x.EndDate.HasValue) ? x.EndDate : DateTime.MaxValue,
        Value = x.Value
    })
    .OrderBy(x => x.EndDate)
    .FirstOrDefault();

var parameter = new Parameter()
    {
        ID = param.ID,
        EndDate = (param.EndDate == DateTime.MaxValue) ? null : param.EndDate,
        Value = param.Value
    };