我有一个Category实体,它有一个Nullable ParentId字段.当下面的方法正在执行且categoryId为null时,结果似乎为null,但是有些类具有null ParentId值.
这里有什么问题,我错过了什么?
public IEnumerableGetSubCategories(long? categoryId) { var subCategories = this.Repository.Categories.Where(c => c.ParentId == categoryId) .ToList().Cast (); return subCategories; }
顺便说一句,当我将条件更改为(c.ParentId == null)时,结果似乎正常.
另一种方式:
Where object.Equals(c.ParentId, categoryId)
要么
Where (categoryId == null ? c.ParentId == null : c.ParentId == categoryId)
首先要做的是进行日志记录,以查看生成的TSQL; 例如:
ctx.Log = Console.Out;
LINQ-to-SQL似乎稍微不一致地处理空值(取决于文字与值):
using(var ctx = new DataClasses2DataContext()) { ctx.Log = Console.Out; int? mgr = (int?)null; // redundant int? for comparison... // 23 rows: var bosses1 = ctx.Employees.Where(x => x.ReportsTo == (int?)null).ToList(); // 0 rows: var bosses2 = ctx.Employees.Where(x => x.ReportsTo == mgr).ToList(); }
所以我所能建议的是使用带有空值的顶部形式!
即
Expression> predicate; if(categoryId == null) { predicate = c=>c.ParentId == null; } else { predicate = c=>c.ParentId == categoryId; } var subCategories = this.Repository.Categories .Where(predicate).ToList().Cast ();
更新 - 我使用自定义"正常"工作Expression
:
static void Main() { ShowEmps(29); // 4 rows ShowEmps(null); // 23 rows } static void ShowEmps(int? manager) { using (var ctx = new DataClasses2DataContext()) { ctx.Log = Console.Out; var emps = ctx.Employees.Where(x => x.ReportsTo, manager).ToList(); Console.WriteLine(emps.Count); } } static IQueryableWhere ( this IQueryable source, Expression > selector, TValue? value) where TValue : struct { var param = Expression.Parameter(typeof (T), "x"); var member = Expression.Invoke(selector, param); var body = Expression.Equal( member, Expression.Constant(value, typeof (TValue?))); var lambda = Expression.Lambda >(body, param); return source.Where(lambda); }
我的猜测是,这是由于DBMS的一个相当常见的属性 - 仅仅因为两个都是空的并不意味着它们是相等的.
要详细说明,请尝试执行以下两个查询:
SELECT * FROM TABLE WHERE field = NULL SELECT * FROM TABLE WHERE field IS NULL
"IS NULL"构造的原因是在DBMS世界中,NULL!= NULL,因为NULL的含义是该值未定义.由于NULL意味着未定义,因此您不能说两个空值相等,因为根据定义您不知道它们是什么.
当您显式检查"field == NULL"时,LINQ可能会将其转换为"field IS NULL".但是当你使用变量时,我猜测LINQ不会自动进行转换.
这是一篇MSDN论坛帖子,其中包含有关此问题的更多信息.
看起来好的"作弊"是将你的lambda改成这样:
c => c.ParentId.Equals(categoryId)
您需要使用运算符Equals:
var subCategories = this.Repository.Categories.Where(c => c.ParentId.Equals(categoryId)) .ToList().Cast();
在以下情况下,等于可以为空的类型返回true:
HasValue属性为false,另一个参数为null.也就是说,根据定义,两个空值相等.
HasValue属性为true,Value属性返回的值等于另一个参数.
并返回false如果:
当前Nullable结构的HasValue属性为true,另一个参数为null.
当前Nullable结构的HasValue属性为false,另一个参数不为null.
当前Nullable结构的HasValue属性为true,Value属性返回的值不等于另一个参数.
更多信息Nullable <.T> .Equals Method