我正在使用EF4通过第三方ADO.NET提供商进行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});但是,如果我在选择之前通过对结果调用ToArray来强制执行,那么我就会得到空引用异常。
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应该返回该类型的默认值。我的类型显然是引用类型,那么为什么query 1不会失败呢?
发布于 2012-10-31 05:53:05
这是因为第一个查询被完全翻译成SQL。当涉及到空“对象”时,SQL与C#是不同的。在SQL中,完全可以编写类似这样的代码
SELECT o.Date, ol.Number FROM Order o LEFT JOIN OrderLine ol ON ... (etc.)当存在没有OrderLine%s的Order%s时,它不会崩溃。在这里的ol上没有空引用异常。对于缺少订单行的ol.Number,SQL只输出null值。
因此,在SQLfirstSQL语句中,匿名类型是直接从从获得的值构建的。整个表达式x.il.item_display_name由DbDataReader的输出填充,如果不存在ilgroup,则输出为null。
在的第二个语句中,首先在内存中构建一个对象数组,由x和il对组成,其中一些对没有il (il为null)。现在,匿名类型是从object数组构建的,表达式x.il.item_display_name尝试从一些不存在的对象中读取item_display_name。
发布于 2012-10-31 04:53:01
这是Entity Framework的一个棘手的特性。当您执行整个查询时,实际上并没有命中数据库。EF只有在你执行ToArray、ToList等操作时才会访问数据库。
在第一个查询中,如果将ToArray()放在末尾,就应该得到NullReference。虽然您实际上并没有执行ToArray,但是当您执行ToList()或ToArray()时,您将只构造要运行的查询。
看看这篇文章:Am I hitting the database?
https://stackoverflow.com/questions/13147341
复制相似问题