【问题标题】:Avoid "Nullable object must have a value." in Linq-To-Sql避免“可空对象必须有值”。在 Linq-To-Sql 中
【发布时间】:2010-12-16 04:30:07
【问题描述】:

我有一个这样的方法查询:

public IList<BusinessObject> GetBusinessObject(Guid? filterId)
{
    using (var db = new L2SDataContext())
    {
        var result = from bo in db.BusinessObjects
                     where (filterId.HasValue)
                               ? bo.Filter == filterId.value
                               : true
                     orderby bo.Name
                     select SqlModelConverters.ConvertBusinessObject(bo);
        return result.ToList();
    }
}

在运行时,这会抛出一个System.InvalidOperationException: Nullable object must have a value.

查看调试器,问题出在我的 Where Clause: Linq To SQL 尝试将整个事情转换为 SQL,所以即使 filterId 为 NULL,它仍然会尝试访问 filterId.value。

我认为/希望 C# 编译器/CLR 会将该 where 子句评估为代码块,并且只将两个分支之一发送到 Linq To SQL,但它不是这样工作的。

我的重构版本有效,但不是很优雅:

public IList<BusinessObject> GetBusinessObject(Guid? filterId)
{
    using (var db = new L2SDataContext())
    {
        var temp = from bo in db.BusinessObjects select bo;
        if(filterId.HasValue) temp = temp.Where(t => t.Filter == filterId.Value);
        var result = from t in temp
                     orderby t.Name
                     select SqlModelConverters.ConvertBusinessObject(bo);
        return result.ToList();
    }
}

我知道延迟评估将确保只发送一个查询,但在其中包含该临时对象并没有那么好。

【问题讨论】:

    标签: c# .net linq-to-sql


    【解决方案1】:

    你试过了吗:

    where filterId == null || t.Filter == filterId
    

    【讨论】:

    • 哇哦,效果很好!它使我免于使用稍微不可读的三级运算符,并解决了由于不必要地访问 filterId.Value 而不仅仅是 filterId 而导致的实际异常。
    【解决方案2】:

    您的修复完全正确。您正在有效地尝试根据您的函数输入动态构建查询。忽略 where 子句而不是提供 WHERE TRUE 是个好主意。如果我正在编写此查询,我会自己使用您的固定版本。

    它不如使用语言关键字漂亮,但在我看来它仍然是处理查询的正确方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-09
      • 1970-01-01
      • 1970-01-01
      • 2012-05-20
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      相关资源
      最近更新 更多