【问题标题】:Linq Query returning null parameters when selecting whole table选择整个表时Linq Query返回空参数
【发布时间】:2015-07-01 10:35:10
【问题描述】:

我对 Linq 很陌生,但最近一直在使用它,并且越来越自信。我正在使用 EF 通过 MVC 项目中的上下文访问我的数据库。

在这种情况下,我想做的就是从我的一张表中获取所有数据。

var msgs = context.Messages.ToList();

我觉得这很好,但是当我以后使用该列表时:

foreach(Message m in msgs)
{

     var info = context.Contacts.Where(x => x.Id == m.recipient.Id)
                                .Select(x => x.MobileNumber).FirstOrDefault();

}

Message 对象有一个强制的Recipient,它是一个联系人对象(我数据库中的另一个实体)。

我在上面的行中得到 NullArgumentException,因为消息对象的 Recipient 参数在我的列表中为空,尽管它们在数据库中不为空。

奇怪的是列表大小合适,所以进入了foreach循环。该列表已正确选择,但根据我的调试器,所有属性均为空。

对此感到困惑,我跑了这条线:

console.WriteLine(context.Messages.Select(x => x.Recipient.FirstName).FirstOrDefault());

第一条消息的收件人的名字被写入控制台。因此,当我单独选择时,我可以检索消息的收件人及其所有信息,但是当尝试检索整个表并将其存储在列表中时,收件人对象为空。

就像我说的,我从包含上下文的 MVC 项目外部访问它。我正在从另一个项目中使用它。然而,这个另一个项目包含对我的 MVC 项目的引用,该项目包含数据库的消息模型,另一个项目包含一个名为 Message 的不同类。这种模棱两可是问题的根源还是我正在做的事情有其他问题?

编辑我显然对我的问题造成了一些混乱。问题是,一旦我检索到列表,列表的大小是正确的,但列表中消息对象的参数为空。例如,如果我写:

foreach (Message m in msgs)
        {

            Console.WriteLine("List Element Exists");
            if (m.Recipient != null)
            {
                Console.WriteLine(m.Recipient.FirstName);
            }
        }

我得到了输出:

List Element Exists List Element Exists List Element Exists List Element Exists

对于列表中的每个元素。

JK

【问题讨论】:

  • Console.WriteLine(String) 不会在 null 参数上抛出异常。告诉确切的地方抛出异常。
  • 当您调试它时,null 是什么确切?对于数据库中该字段为null 的任何记录,我希望m.Text 将是null
  • 如果 m 为 null 可能是映射问题。另外,是字符串类型的文本并直接映射到表格吗?
  • 文本是数据库中的必填字段吗?
  • 我很抱歉我简化了问题以尝试显示孤立的问题。请看编辑。空异常是指我的消息的收件人对象。我的消息有一个必需的收件人,它是一个联系人(我的数据库中的另一个实体)。

标签: c# asp.net-mvc linq entity-framework


【解决方案1】:

where 条件的结果很可能在 linq 查询中为 null。

var info = context.Contacts.Where(x => x.Id == m.recipient.Id)
                                .Select(x => x.MobileNumber).FirstOrDefault()

另外查询本身也有一些问题,你可以写同样的查询:

var mobileNumber = string.Empty; //if it is not a string then initialize with proper value
var info = context.Contacts.FirstOrDefault(x => x.Id == m.recipient.Id);
if(info != null)
    mobileNumber = info.MobileNumber;

还有另一个问题;如果你执行这一行:

var msgs = context.Messages.ToList();

它将从数据库中获取所有Messages;但您只需要一个电话号码。因此,无需获取所有记录,只需执行我提供的查询,不要调用 foreach。

编辑

ToList()被执行时,立即执行db查询;这意味着不会加载Message 对象的Recipient 属性。根据您使用的是延迟加载还是急切加载,您需要另一种机制来获取Recipient 属性。类似的东西;

var msgs = context.Messages.Include(b => b.Recipients).ToList();

【讨论】:

  • 感谢您的回复。这仍然会抛出异常。例外是因为某种原因Recipient 联系人对象在我的消息列表中为空。我检索所有消息的原因是因为我在 Foreach 循环中以其他方式使用该列表。你看到的那一行是一个大流程的第一行。我需要所有的消息....
  • 我以前从未遇到过 include 函数……但感谢它运行良好。所以我猜你必须指定复杂的属性才能包含它们。
【解决方案2】:

如果您希望 msg.Recipient 包含某些内容(即在 DB 上编译数据),则这是一个映射问题。最常见的问题是 Recipient 属性未标记为虚拟。

编辑
或者,更糟糕的是,该类被标记为密封,但这通常不会发生

【讨论】:

  • 我不知道延迟加载与急切加载,因为我对这个领域还很陌生。我只能接受一个答案,但我投了赞成票,因为我从两者中都学到了一些东西。谢谢。您认为使用急切加载仅加载特定情况下需要的内容的优势是否更可取?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-10
  • 1970-01-01
  • 1970-01-01
  • 2018-04-22
  • 1970-01-01
相关资源
最近更新 更多