实体框架错误:使用PredicateBuilder进行异常并比较空值

时间:2012-12-21 21:32:16

标签: c# entity-framework entity-framework-4 predicatebuilder

我能够在LinqPad中运行我的方法(下面),但是当切换到我的实际代码(使用Entity Framework)时,我收到此错误:

  

“无法将类型'System.Nullable`1'强制转换为'System.Object'。   LINQ to Entities仅支持转换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是可以为空的小数。问题是那些变量可以为空,我们甚至想要将结果过滤为null。这不适用于EF,还是有一种优雅的方式呢?

修改

要明确的是,当manufacturerId作为null传入时,使用此行返回五行(我可以通过查看数据库来验证):

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时,我得到上面的错误。

1 个答案:

答案 0 :(得分:3)

来自Bob Horn的编辑/备注:由于下面的编辑,此答案已被接受,指定了EF中的错误。这个答案的第一部分没有用。

通过使用object.Equals(object, object)作为比较两种值类型的方法(Nullables也是值类型),您将隐式装箱。实体框架不支持此功能。

请尝试使用==运算符:

// 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

Hacky修复了​​您当前的版本:

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

但如果您的应用程序允许,请升级到EF5。