实体框架Bug: PredicateBuilder和比较null的异常



我能够让我的方法(下面)在LinqPad中运行,但是当切换到我的实际代码(使用实体框架)时,我得到这个错误:

"无法强制转换类型'System '。类型'System.Object'可为空' 1'。LINQ到实体只支持转换EDM原语或枚举类型。"

如果我取消注释这里的两个注释行中的任何一个,就会发生错误(实际的错误直到运行方法中的最后一行才发生):

public List<LotEquipmentScan> GetLotEquipmentScans(string maximoAssetNumber, decimal? manufacturerId, decimal? partNumber)
{
    var predicate = PredicateBuilder.True<LotEquipmentScanRecord>();
    // Note: Can't use == in where clause because of the possibility of nulls. That's why we're using object.Equals().
    if (maximoAssetNumber != "x") { predicate = predicate.And(scan => object.Equals(scan.MaximoAssetNumber, maximoAssetNumber)); }
    //if (manufacturerId != -1) { predicate = predicate.And(scan => object.Equals(scan.RawMaterialLabel.ManufacturerId, manufacturerId)); }
    //if (partNumber != -1) { predicate = predicate.And(scan => object.Equals(scan.RawMaterialLabel.PartNumber, partNumber)); }
    return Db.LotEquipmentScanRecords.AsExpandable().Where(predicate).ToList().Map();
}

我相信这是因为manufacturerId和partNumber是可空小数。问题是这些变量可以为空,我们甚至希望通过它们为空来过滤结果。这对EF是不适用的,还是有一种优雅的方法?

编辑

要清楚,当manufacturerId作为null传入时,使用这一行返回五行(我可以通过查看DB来验证):

if (manufacturerId != -1) { predicate = predicate.And(scan => object.Equals(scan.RawMaterialLabel.ManufacturerId, manufacturerId)); }

使用这行,不返回任何行:

if (manufacturerId != -1) { predicate = predicate.And(scan => scan.RawMaterialLabel.ManufacturerId == manufacturerId); }

问题是当我传入一个好的manufacturerId,然后我得到上面的错误。

Bob Horn的注释:这个答案被接受是因为下面的Edit,指定了EF中的一个bug。这个答案的第一部分不起作用。

通过使用object.Equals(object, object)作为比较两个值类型的方法(空值也是值类型),您隐式地将它们装箱。实体框架不支持这个

尝试使用==操作符:

// Since scan.RawMaterialLabel.ManufacturerId and manufacturerId are both Nullable<T> of the 
// same type the '==' operator should assert value equality, whether they have a value, or not.
// (int?)1 == (int?)1
// (int?)null == (int?)null
// (int?)1 != (int?)null
predicate = predicate.And(scan => scan.RawMaterialLabel.ManufacturerId == manufacturerId);

对于值类型,==运算符断言值相等,类似于object.Equals()对引用类型所做的。

编辑:

经过进一步调查,似乎在旧版本的EF (EF5之前)中存在一个bug。

修改当前版本:

predicate = predicate.And(scan => 
   manufacturerId.HasValue
     ? scan.RawMaterialLabel.ManufacturerId == manufacturerId
     : scan.RawMaterialLabel.ManufacturerId == null);

但如果你的应用程序允许,升级到EF5

最新更新