带有嵌套对象的联合上的 LINQ to Entities 空引用
Posted
技术标签:
【中文标题】带有嵌套对象的联合上的 LINQ to Entities 空引用【英文标题】:LINQ to Entities null reference on Union with nested objects 【发布时间】:2016-04-08 11:33:02 【问题描述】:给定以下类结构:
public class User // DB model
public Guid Id get; set;
public Address Address get; set;
// And other propeties
public class Invitation // DB model
public Guid Id get; set;
// And other propeties
public class Address // DB model
public string Zip get; set;
// And other properties
public class ResponseModel
public Guid Id get; set;
public ResponseAddress Address get; set;
public class ResponseAddress
public string Zip get; set;
// And other properties
以下查询分别返回用户和邀请,目的是获得两个查询的联合:
var users = db.Users.Select(x => new ResponseModel()
Id = x.Id,
Address = new ResponseAddress()
Zip = x.Address.Zip
);
var invitations = db.Invitations.Select(x => new ResponseModel()
Id = x.Id,
Address = new ResponseAddress()
Zip = String.Empty
);
var union = users.Union(invitations).ToList();
当我尝试执行联合数据库端时,我在 System.Data.Entity.CoreQuery.PlanCompiler 的深处得到一个空引用异常。如果我分别在每个部分上调用 ToList() ,它就可以工作;如果我在每个部分上调用 ToList() 然后合并它们,它就可以工作。
users.ToList();
invitations.ToList();
users.ToList().Union(invitations.ToList());
如果我在创建 ResponseAddress 部分之前合并它们,然后在稍后调用 Select 时创建 ResponseAddress 部分,它似乎也可以工作:
var users = db.Users.Select(x => new
Id = x.Id,
Zip = x.Address.Zip
);
var invitations = db.Invitations.Select(x => new
Id = x.Id,
Zip = String.Empty
);
var union = users.Union(invitations).Select(x=>new ResponseModel()
Id = x.Id,
Address = new ResponseAddress()
Zip = x.Zip
).ToList();
关于为什么在第一组查询中调用 Union 会返回空引用异常,而在最后一个查询中调用不会返回有什么想法吗?两者都在 DB 端执行,并且都应该产生相似的查询(理论上几乎相同,除了 LINQ 进行查询嵌套的方式。)
【问题讨论】:
您可以在IQueryable
上使用ToString()
查看查询
另外我在您的模型中没有看到任何 virtual
关键字,这是加载相关实体所必需的
【参考方案1】:
在 ResponseAddress 部分,您创建 ResponseAddress 类的新实例。这对关系数据库没有意义。当您将查询结果转换为列表时,处理联合是运行时的工作,它知道对象,而数据库服务器不知道 ResponseAddress,因为它不是表示数据的方式。
【讨论】:
【参考方案2】:DbSet 和 IDbSet 实现 IQueryable 意味着执行查询 仅在以下情况下针对数据库:
-
它由 foreach (C#) 或 For Each (Visual Basic) 枚举
声明。
由ToArray等集合操作枚举,
ToDictionary 或 ToList。
在最外层指定了诸如 First 或 Any 等 LINQ 运算符
查询的一部分。
调用以下方法: DbSet、DbEntityEntry.Reload 和 Database.ExecuteSqlCommand
var users = db.Users.Select(x => new Id = x.Id, 邮编 = x.地址.邮编 );
因为它是 IQueryable 上面的查询还没有对数据库执行,用户是一个空集合而不是 null
var users = db.Users.Select(x => new
Id = x.Id,
Zip = x.Address.Zip
).ToList();
现在调用 ToList() 已经执行了对 db 的查询。
【讨论】:
以上是关于带有嵌套对象的联合上的 LINQ to Entities 空引用的主要内容,如果未能解决你的问题,请参考以下文章
如何关联不同 dbml 图上的 Linq-To-Sql 对象?
Linq XML to Object,其中 xml 节点具有嵌套元素