【问题标题】:Code First Entity Framework Linq Statement Returning Missing RecordsCode First Entity Framework Linq 语句返回缺失记录
【发布时间】:2014-04-29 17:20:53
【问题描述】:

我有以下疑问:

orderMessageEmail.MessageChain = DbContext.Current
    .Messages
    .Where(c => 
        c.OrderId == orderMessageEmail.OrderId && 
        c.IsPublic && 
        c.MessageId != orderMessageEmail.MessageId && 
        c.MessageId < orderMessageEmail.MessageId
    )
    .Select(c => new OrderMessageChain()
    {
        CreateDateTime = c.CreateDateTime,
        MessageId = c.MessageId,
        Message = c.MessageData,
        UserFirstName = c.User.FirstName,
        UserLastName = c.User.LastName,
        CustomerFirstName = c.CustomerAccountPerson.FirstName,
        CustomerLastName = c.CustomerAccountPerson.LastName,
        SentFrom = c.SentFrom
    })
    .OrderByDescending(c => c.MessageId)
    .Take(10)
    .ToList();

我遇到的问题是,只要c.User 为空,它就不会返回OrderMessageChain 的任何记录

我想让它返回 UserFirstNameUserLastName 作为空字符串,而不是从列表中完全消除 OrderMessageChain

这有意义吗?

还有一件事..

简单地测试这个查询:

var t = DbContext.Current
        .Messages
        .Include("User")
        .Where(c => 
         c.MessageId < 138120 && 
         c.OrderId == 170496 && 
         c.IsPublic)
         .ToList();

当我在数据库中手动执行相同的查询时,我显示了 3 条记录,但是 t 显示为零。

我一直认为 Include 可以用作左连接 - 不是这样吗?

还有一件事......

好的,所以我想我开始意识到这里发生了什么......

我没有意识到这一点,但似乎 DBA 将消息表上的 DB 字段 UserId 设置为不可为空,但是,在没有用户记录的情况下,UserId 字段包含0(零)值,而不是 null...啊...

我认为这导致代码首先相信它应该执行内部联接而不是左联接per here

所以我不太确定如何解决这个问题。无论如何我可以强制代码首先以某种方式对该导航属性执行左连接而不是内部?

【问题讨论】:

  • DbContext.Current.Include("User").....
  • Include 应与表达式 (.Include( c =&gt; c.User )) 一起使用,以获得最佳实践。除此之外,include 语句不会影响从数据库接收到的记录数量。问题必须与 where 语句有关。我建议,纯粹出于测试目的和您自己的理智:),迭代地执行 and 子句,然后检查它们的计数以查看哪个删除了所有内容。伪var t1 = db.cur.m.where(c.mid &lt; 138); int c1 = t1.Count(); var t2 = t1.where(c.oid == 170); int c2 = t2.Count(); var t3 = t2.where(c.ispublic); int c3 = t3.Count();
  • 如果我删除 Include("User") 记录会出现 - 唯一糟糕的是我想把它放在那里,所以当有匹配的用户记录时,我可以提取名称: (

标签: c# asp.net linq ef-code-first


【解决方案1】:

您应该能够选择所需的数据,将其转换为 IEnumerable 并在内存中进行映射,例如(未经测试的);

orderMessageEmail.MessageChain = DbContext.Current
    .Messages
    .Where(c => 
        c.OrderId == orderMessageEmail.OrderId && 
        c.IsPublic && 
        c.MessageId != orderMessageEmail.MessageId && 
        c.MessageId < orderMessageEmail.MessageId
    )
    .OrderByDescending(c => c.MessageId)
    .Take(10)
    .Select(c => new {
        c, u = c.User, cap = c.CustomerAccountPerson
    }). 
    .AsEnumerable()
    .Select(c => new OrderMessageChain()
    {
        CreateDateTime = c.c.CreateDateTime,
        MessageId = c.c.MessageId,
        Message = c.c.MessageData,
        UserFirstName = c.u == null ? "" : c.u.FirstName,
        UserLastName = c.u == null ? "" : c.u.LastName,
        CustomerFirstName = c.cap == null ? "" : c.cap.FirstName,
        CustomerLastName = c.cap == null ? "" : c.cap.LastName,
        SentFrom = c.c.SentFrom
    })
    .ToList();

【讨论】:

  • 有趣 - 我也会试试这个,我更新了我的问题,发现更多我认为是问题的原因,不确定这是否会改变任何事情
  • @99823 啊,您对问题的最后补充可能也会使这个问题成为问题。你总是可以测试,但我怀疑它可能会以同样的方式失败。
  • 我对您的解决方案犹豫不决的一件事是,每当我拉消息并想要包含用户时,我将不得不做一些疯狂的修改,而不是仅仅使用包含语句 - 知道我的意思是说?并不是说您的解决方案不起作用,我只是希望我不必经历所有额外的事情:p
  • @99823 如果您需要它是自动的,您很可能需要更新映射。
  • 是的 - 我只是让代码第一个 UserId 属性可以为空,让表保持不变并且查询按我想要的那样工作,我只是担心我会遇到一些问题但是,如果我没有正确修复表格,则使用此设置,但这会引入一个全新的蠕虫罐来处理我们使用该数据库的旧应用程序...啊.. 绝非易事;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多