【问题标题】:Linq help - sub query gives null pointer exceptionLinq 帮助 - 子查询给出空指针异常
【发布时间】:2015-07-04 17:26:21
【问题描述】:

我编写了一个电子邮件系统,其中我们有一个用户表“tblUsers”和一个消息表。一个用户的收件箱中可以有许多消息(来自 tblusers 中的其他用户)(one:many)。

在 tblUsers 表中,我有一个名为 ImageURL(字符串)的列,其中包含用户头像的 URL。在这种情况下,我正在循环浏览属于用户的收件箱中的消息,而我想要做的是,一旦我收到消息,就沿着树走到 tblUser 并获取 ImageURL 列中的值该邮件的所有者,在下面标记为“SenderAvatar”。

这是我尝试过的。问题是下面的 SenderAvatar 的子 linq 抛出了一个空指针异常,即使我已经确认 ImageURL 有一个值(这是 dev 所以只有三个用户)。不知何故,我的逻辑和 linq 的逻辑在这里不一致。有人可以帮忙吗?谢谢!

编辑 我发现了两个错误。第一个错误是Dzienny 指出了我比较苹果和橙子的正确方向。第二个错误是FromUserId = ux.tblUserId,,我将当前用户ID 设置为FromUserId 伙计们,感谢您对此提供的所有帮助。

 public List<UserInboxMsg> GetUserInboxMsg(IKASLWSEntities conx, int userid)
    {
        var u = (from m in conx.tblUsers where m.Id == userid select m).FirstOrDefault();
        if (u != null)
        {

            return (from ux in u.tblInboxes
                    orderby ux.CreationTS descending
                    select new UserInboxMsg
                    {
                        CreationTS = ux.CreationTS,
                        ExpirationDate = ux.ExpirationDate,
                        FromUserId = ux.tblUserId,
                        HasImage = ux.HasImage,
                        ImageId = ux.ImageId ?? 0,
                        IsDeleted = ux.IsDeleted,
                        IsRead = ux.IsRead,
                        MsgId = ux.Id,
                        MsgSize = ux.MessageSize,
                        ParentId = ux.ParentId,
                        Title = ux.Title,
                        ToUserId = userid,
                        FromUserName = ux.Title,
                        SenderAvatar = conx.tblMessages.Where(mu=>mu.Id == ux.Id).FirstOrDefault().tblUser.ImageURL,
                        Message = ux.Message
                    }).ToList<UserInboxMsg>();
        }
        else
        {
            return new List<UserInboxMsg>();
        }
    }

}

【问题讨论】:

  • 您是否将邮件 ID 与收件箱 ID mu.Id == ux.Id 进行比较?
  • @Dzienny 谢谢!这是一个很大的帮助

标签: c# linq entity-framework subquery


【解决方案1】:

如果在实体框架中,两个表之间存在外键引用,您可能会这样做:

SenderAvatar = conx.tblMessages.FirstOrDefault( mu=>mu.Id == ux.Id).ImageURL,

【讨论】:

  • 谢谢。我复制并粘贴了您的解决方案,VS 说 ImageURL 不存在,这是有道理的,因为在这种情况下,我们正在抓取没有名为 ImageURL 的属性的 tblMessage 对象。 ImageURL 是 tblUser 中的上一级。
【解决方案2】:

试试这个。

   public List<UserInboxMsg> GetUserInboxMsg(IKASLWSEntities conx, int userid)
        {
            var u = (from m in conx.tblUsers where m.Id == userid select m).FirstOrDefault();
            if (u != null && conx != null)

        {

            return (from ux in u.tblInboxes
                    orderby ux.CreationTS descending
                    select new UserInboxMsg
                    {
                        ...
                        ...
                        SenderAvatar = conx.tblMessages.Any(mu=>mu.Id == ux.Id) ? (conx.tblMessages.First(mu=>mu.Id == ux.Id).tblUser != null? conx.tblMessages.First(mu=>mu.Id == ux.Id).tblUser.ImageURL : null) : null,
                        Message = ux.Message
                    }).ToList<UserInboxMsg>();
        }
        else
        {
            return new List<UserInboxMsg>();
        }
    }

}

如果您的 Avatar 为 null,可能是因为 tblMessages 中没有 mu.Id 等于 ux.Id 的条目,或者存在 tblMessage 条目但 tblUser 属性为 null

【讨论】:

  • 谢谢。我尝试了您的代码,但 ImageURL 为空。
  • 我已经添加到答案中,查看最后一部分
【解决方案3】:

这里有几个问题。

第一个是第二个语句在内存中执行,同时可以让整个查询作为SQL运行:

from u in conx.tblUsers where m.Id == userid
from ux in u.tblInboxes
orderby ux.CreationTS descending
select new UserInboxMsg
{
    CreationTS = ux.CreationTS,
    ExpirationDate = ux.ExpirationDate,
    FromUserId = ux.tblUserId,
    HasImage = ux.HasImage,
    ImageId = ux.ImageId ?? 0,
    IsDeleted = ux.IsDeleted,
    IsRead = ux.IsRead,
    MsgId = ux.Id,
    MsgSize = ux.MessageSize,
    ParentId = ux.ParentId,
    Title = ux.Title,
    ToUserId = userid,
    FromUserName = ux.Title,
    SenderAvatar = conx.tblMessages.Where(mu => mu.Id == ux.Id)
                       .FirstOrDefault().tblUser.ImageURL,
    Message = ux.Message
}

这有三个好处:

  • 您从数据库中获取的数据更少
  • 您摆脱了空引用异常,因为 SQL 没有空引用。如果没有找到记录,它只会返回 null。
  • 您可以在不使用 if-else 的情况下返回此语句的结果。

其次,不太重要的是,您应该使用类似Inbox.Messages 的导航属性,而不是加入(某种程度)收件箱及其消息。这降低了您使用错误连接变量的可能性,并压缩了您的代码:

SenderAvatar = ux.Messages.
                 .FirstOrDefault().User.ImageURL,

现在如果没有头像,那么就是没有头像。并且没有空引用异常。

(顺便说一句,你可以看到我讨厌类和属性名称中的这些前缀)。

【讨论】:

  • 谢谢。好东西。会的。
【解决方案4】:

我只能猜测您的这部分代码是错误的:SenderAvatar = conx.tblMessages.Where(mu=&gt;mu.Id == ux.Id).FirstOrDefault().tblUser.ImageURL 例如,我认为您应该使用 (mu=>mu.UserId == ux.Id) 而不是 (mu=>mu.Id == ux.Id)。在您的代码中,您将一个表的“Id”与另一个表的“Id”进行比较,这通常在一对多关系中是错误的。 (仅适用于一对一关系)

我说我可以猜到,因为您没有提及有关 tblInboxestblMessages 字段的任何信息。如果您可以向我提供有关其结构的更多信息,我可以更详细地回答。

顺便说一下,让你的代码更清晰,你可以使用:

var u = conx.tblUsers.FirstOrDefault(m=>m.Id == userid);

而不是

var u = (from m in conx.tblUsers where m.Id == userid select m).FirstOrDefault();

conx.tblMessages.FirstOrDefault(mu=>mu.Id == ux.Id)

而不是

conx.tblMessages.Where(mu=>mu.Id == ux.Id).FirstOrDefault()

【讨论】:

  • 这就是 OP 所说的苹果和橙子 :)
  • 是的,他在我写答案时编辑了他的帖子:D
  • @AfshinAghazadeh 伟大的指针(谢谢!)。我沉浸在自己的困惑中,感谢大家提供的所有救生圈。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-06
  • 2014-07-19
  • 2017-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多