Linq到实体DefaultIfEmpty [英] Linq to Entities DefaultIfEmpty

查看:209
本文介绍了Linq到实体DefaultIfEmpty的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过第三方ADO.NET提供程序将EF 4用于PostgreSQL.在我的数据源中,没有任何根据该连接条件匹配项目的项目行.出于这个原因,我希望查询1基于空引用异常而失败.但是,它完成了,并为il上的每个属性提供了默认的值类型. item_display_name是一个字符串,因此ilName设置为null. ilStartDate设置为DateTime的默认值. x.il.item_id和x.il.item_line_no均为0.

I'm using EF 4 to PostgreSQL using a 3rd party ADO.NET provider. In my data source, I have no item lines that match items based on this join condition. For this reason I expect query 1 to fail based on a null reference exception. However, it completes and gives me value type defaults for each of the properties on il. item_display_name is a string so ilName is set to null. ilStartDate is set to DateTime's default. x.il.item_id and x.il.item_line_no are both 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来强制执行,则会得到空引用异常.

However, if I force execution by calling ToArray on my results before the Select, I then get my null reference exception.

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

To my understanding, DefaultIfEmpty should return the default for that type. My type is clearly a reference type, so why won't query 1 fail?

推荐答案

这是因为第一个查询已完全转换为SQL.对于空的对象",SQL与C#不同.在SQL中,完全可以写类似

This is because the first query is completely translated into SQL. SQL is different than C# when it comes to null "objects". In SQL it is perfectly OK to write something like

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

当有Order个不带OrderLine的时,它不会崩溃.此处ol上没有空引用异常. SQL只会为缺少订单行的ol.Number输出空值.

It won't crash when there are Orders without OrderLines. No null reference exception on ol here. SQL just outputs null values for ol.Number where order lines are missing.

因此,在 first 语句中,匿名类型是直接从从SQL获取的值中构建的.整个表达式x.il.item_display_nameDbDataReader的输出填充,当不存在ilgroup时为空.

So in the first statement the anonymous type is built directly from values obtained from SQL. The whole expression x.il.item_display_name is populated by output from a DbDataReader, which is null when no ilgroup is present.

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

In the second statement, first an array of objects is built in memory, consisting of x and il pairs, some which have no il (il is null). Now the anonymous type is built from the object array and the expression x.il.item_display_name tries to read item_display_name from some non-existing objects.

这篇关于Linq到实体DefaultIfEmpty的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆