我正在使用第三方ADO.NET提供商将EF 4用于PostgreSQL。在我的数据源中,我没有基于此连接条件匹配项目的项目行。出于这个原因,我希望查询1基于空引用异常而失败。但是,它完成并为我提供了il上每个属性的值类型默认值。 item_display_name是一个字符串,因此ilName设置为null。 ilStartDate设置为DateTime的默认值。 x.il.item_id和x.il.item_line_no均为0.
var query1 =
_db.items
.GroupJoin(_db.item_line.Where(x => x.start_date == selectedStartDate), x => x.item_id, il => il.item_id, (x, ilgroup) => new { x, ilgroup })
.SelectMany(x => x.ilgroup.DefaultIfEmpty(), (x, il) => new { x.x, il })
.Select(x =>
new
{
itemId = x.x.item_id,
ilName = x.il.item_display_name,
ilStartDate = x.il.start_date,
ilItemId = x.il.item_id,
orderLine = x.il.item_line_no});
但是,如果我在Select之前通过调用ToArray来强制执行,那么我会得到我的null引用异常。
var query2 =
_db.items
.GroupJoin(_db.item_line.Where(x => x.start_date == selectedStartDate), x => x.item_id, il => il.item_id, (x, ilgroup) => new {x, ilgroup})
.SelectMany(x => x.ilgroup.DefaultIfEmpty(), (x, il) => new {x.x, il}).ToArray()
.Select(x =>
new
{
itemId = x.x.item_id,
ilName = x.il.item_display_name,
ilStartDate = x.il.start_date,
ilItemId = x.il.item_id,
orderLine = x.il.item_line_no});
据我了解,DefaultIfEmpty应返回该类型的默认值。我的类型显然是一个引用类型,为什么不查询1失败?
答案 0 :(得分:2)
这是因为第一个查询完全转换为SQL。当涉及null“对象”时,SQL与C#不同。在SQL中,写出像
这样的东西是完全可以的SELECT o.Date, ol.Number FROM Order o LEFT JOIN OrderLine ol ON ... (etc.)
如果Order
没有OrderLine
,则不会崩溃。这里ol
没有空引用异常。 SQL只输出缺少订单行的ol.Number
的空值。
因此,在第一个语句中,匿名类型直接根据从SQL获取的值构建。整个表达式x.il.item_display_name
由DbDataReader
的输出填充,当没有ilgroup
时为空。
在 second 语句中,首先在内存中构建一个对象数组,其中包含x
和il
对,其中一些没有il
( il
为空)。现在,匿名类型是从对象数组构建的,表达式x.il.item_display_name
尝试从一些不存在的对象中读取item_display_name
。
答案 1 :(得分:0)
这是实体框架的一个棘手特征。当您执行整个查询时,实际上并没有命中数据库。当您执行ToArray,ToList等时,EF只会进入数据库...
在第一个查询中,如果将ToArray()放在最后,则应该获取NullReference。虽然您实际上并没有执行ToArray,但您只需构建要在执行ToList()或ToArray()时运行的查询。
看一下这篇文章:Am I hitting the database?