实体框架中的可空实体投影

Posted

技术标签:

【中文标题】实体框架中的可空实体投影【英文标题】:Nullable entity projection in Entity Framework 【发布时间】:2010-09-13 12:14:56 【问题描述】:

我有以下 SQL Server 2005 数据库架构:

CREATE TABLE Messages (
   MessageID int,
   Subject varchar(500),
   Text varchar(max) NULL,
   UserID NULL
)

“UserID”列 - 可以为空 - 是一个外键并链接到表

CREATE TABLE Users (
   UserID int,
   ...
)

现在我有几个名称为 Message、User 等的 POCO 类,我在以下查询中使用它们:

public IList<Message> GetMessages(...) 
  var q = (from m in dataContext.Messages.Include("User")
           where ...
           select m); // could call ToList(), but...

  return (from m in q
          select new Message 
            ID = m.MessageID,
            User = new User 
              ID = m.User.UserID,
              FirstName = m.User.FirstName,
              ...
            
          ).ToList();

现在请注意,我建议实体框架 - 使用 Include("Users") - 加载与消息关联的用户(如果有)。另请注意,我没有在第一个 LINQ 语句之后调用 ToList() 。通过这样做,只会从数据库返回投影列表中的指定列(在本例中为 MessageID、UserID、FirstName)。

这就是问题所在 - 一旦 Entity Framework 遇到 UserID == NULL 的消息,它就会抛出异常,说它无法转换为 Int32,因为 DB 值为 NULL。

如果我将最后几行更改为

return (from m in q
        select new Message 
           ID = m.MessageID,
           User = m.User == null ? null : new User 
              ID = m.User.UserID,
              ...
           
        ).ToList()

然后抛出一个运行时 NotSupportedException 告诉它不能创建一个常量用户类型,并且只支持像 int、string、guid 这样的原语。

除了在第一条语句之后立即实现结果并在之后使用内存中投影之外,任何人都知道如何处理它?谢谢。

【问题讨论】:

您要投射到的消息类型是否与 m 的类型不同?你为什么要投射? 为什么要构造新的 Message 和 User 对象,而不是仅仅使用从 q 中返回的那些?我认为你没有完全正确地使用框架。 @DavidB:Message是POCO,m是Entity类。 @Orion Adrian:嗯,我希望以后能缓存查询结果。对于实体对象,您需要手动 Detach() 它们 - 包括所有依赖对象,例如用户在这种情况下,太麻烦了(LINQ2SQL 也有同样的问题)。 【参考方案1】:

您忘记包含“消息”类的声明,但我怀疑该类中的 UserID 属性未声明为可空类型。如果是这种情况,请将其从“int”更改为“int?” (可为空的 int)。

【讨论】:

我认为MS论坛上的这个讨论也适用。它可能与此答案所暗示的相同。 social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/…【参考方案2】:

我怀疑你们的关系不是一对一的。

【讨论】:

对,这是1:n的关系,一条消息只属于1个用户,但一个用户可以有多个消息。 m.Users 属性有什么作用?我认为那是一堆与消息相关联的用户。 好的,m.Users 实际上应该是 m.User,我已经在原始问题中更改了它。此属性是指向提交此消息的用户的实体。【参考方案3】:

由于您执行了.Include("Users"),您应该能够只遍历Message 对象中的User 属性来获取您想要的信息。

【讨论】:

是的,我就是这样做的,除非没有用户与消息关联(记住,UserID 可以为空)。 如果没有用户对象,那么您需要一个空值。你在寻找什么?

以上是关于实体框架中的可空实体投影的主要内容,如果未能解决你的问题,请参考以下文章

实体框架中的可选一对多关系[关闭]

jpa中的可空映射映射

最有效的实体框架代码第一方法展平/投影具有特定子实体的父实体

使用实体框架中的可选记录级联删除

减少投影的实体框架问题

如何创建可重用的实体框架投影表达式?