Linq to Entities DefaultIfEmpty

时间:2012-10-30 20:47:20

标签: .net linq entity-framework-4

我正在使用第三方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失败?

2 个答案:

答案 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_nameDbDataReader的输出填充,当没有ilgroup时为空。

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

答案 1 :(得分:0)

这是实体框架的一个棘手特征。当您执行整个查询时,实际上并没有命中数据库。当您执行ToArray,ToList等时,EF只会进入数据库...

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

看一下这篇文章:Am I hitting the database?