1

我正在使用 EF 4 到 PostgreSQL 使用 3rd 方 ADO.NET 提供程序。在我的数据源中,我没有与基于此连接条件的项目匹配的项目行。出于这个原因,我希望查询 1 基于空引用异常而失败。但是,它完成并为我提供了 il 上每个属性的值类型默认值。item_display_name 是一个字符串,因此 ilName 设置为空。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 来强制执行,则会得到空引用异常。

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 不会失败?

4

2 回答 2

2

这是因为第一个查询完全翻译成 SQL。当涉及到空“对象”时,SQL 与 C# 不同。在 SQL 中,编写类似的东西是完全可以的

SELECT o.Date, ol.Number FROM Order o LEFT JOIN OrderLine ol ON ... (etc.)

Orders 没有OrderLines 不会崩溃。这里没有空引用异常olol.NumberSQL 只为缺少订单行的地方输出空值。

所以在第一个语句中,匿名类型是直接从 SQL 获得的值构建的。整个表达式x.il.item_display_name由 a 的输出填充,当 no存在DbDataReader时为 null 。ilgroup

第二个语句中,首先在内存中构建一个对象数组,由xil对组成,其中一些没有ilil为空)。现在匿名类型是从对象数组构建的,并且表达式x.il.item_display_name尝试item_display_name从一些不存在的对象中读取。

于 2012-10-30T21:53:05.127 回答
0

这是实体框架的一个棘手特性。当您执行整个查询时,您实际上并没有访问数据库。EF 只会在您执行 ToArray、ToList 等操作时进入数据库...

在第一个查询中,如果您将 ToArray() 放在末尾,您应该会获得 NullReference。虽然您实际上并没有执行 ToArray,但您只会在执行 ToList() 或 ToArray() 时构建要运行的查询。

看看这篇文章:我在访问数据库吗?

于 2012-10-30T20:53:01.090 回答