代码之家  ›  专栏  ›  技术社区  ›  Pure.Krome

有人能解释一下这两个linq查询返回不同结果的原因吗?

  •  11
  • Pure.Krome  · 技术社区  · 14 年前

    我有两个linq(到EF4)查询,它们返回不同的结果。第一个查询 正确的结果,但格式/投影不正确。

    第二个查询是我想要的,但是它缺少一些数据。

    alt text http://img220.imageshack.us/img220/9678/schema.png

    问题1

    var xxxx = (from cp in _connectedClientRepository
                .GetConnectedClients(new[] { "LogEntry", "LogEntry.GameFile" })
                .AsExpandable()
                .Where(predicate)
                select cp)
        .ToList();
    

    alt text http://img231.imageshack.us/img231/6541/image2ys.png

    注意财产 GameFile 无效的。这很好:)注意到linq查询了吗?我是 急装 LogEntry 然后迫不及待地 游戏文件 (对于每个急切加载的日志项)。

    这就是我想要的->每个 那是紧急装载,请紧急装载 游戏文件 . 但是这个投影结果是错误的。。。

    好 啊。。下一个。。。

    问题2

    var yyy = (from cp in _connectedClientRepository
                .GetConnectedClients(new[] { "LogEntry", "LogEntry.GameFile" })
                .AsExpandable()
                .Where(predicate)
            select cp.LogEntry)
        .ToList();
    

    alt text

    :上面的图片有一个印刷错误。。。请注意,输入的include associations代码是正确的(即。 LogEntry.GameFile )当图像被打错的时候。

    LogEntries 结果。但请注意 属性现在为空?我不知道为什么:(我想我应该是迫不及待地装上了正确的链子。这是正确的投影,但结果不正确。

    必需的存储库代码。

    public IQueryable<ConnectedClient> GetConnectedClients(
        string[] includeAssociations)
    {
        return Context.ConnectedClients
            .IncludeAssociations(includeAssociations)
            .AsQueryable();
    }
    
    public static class Extensions
    {
        public static IQueryable<T> IncludeAssociation<T>(
            this IQueryable<T> source, string includeAssociation)
        {
            if (!string.IsNullOrEmpty(includeAssociation))
            {
                var objectQuery = source as ObjectQuery<T>;
    
                if (objectQuery != null)
                {
                    return objectQuery.Include(includeAssociation);
                }
            }
    
            return source;
        }
    
        public static IQueryable<T> IncludeAssociations<T>(
            this IQueryable<T> source, params string[] includeAssociations)
        {
            if (includeAssociations != null)
            {
                foreach (string association in includeAssociations)
                {
                    source = source.IncludeAssociation(association);
                }
            }
    
            return source;
        }
    }
    

    • 1:修正了代码示例中注意到的一些输入错误。
    • 2:添加了存储库代码以帮助任何困惑的人。
    3 回复  |  直到 5 年前
        1
  •  2
  •   jeroenh    14 年前

    我怀疑Craig Stuntz的建议可能有效,但如果无效,以下建议肯定有效:

     var xxxx =_connectedClientRepository
            .GetConnectedClients(new[] { "LogEntry", "LogEntry.GameFile" })
            .AsExpandable()
            .Where(predicate)
            .ToList() // execute query
            .Select(cp => cp.LogEntry); // use linq-to-objects to project the result
    
        2
  •  1
  •   Craig Stuntz    14 年前

    Include() 处理查询结果,而不是中间查询。你可以阅读更多关于 包含() 包含() 对于整个查询,如下所示:

    var q = ((from cp in _connectedClientRepository.GetConnectedClients()
                                                   .AsExpandable()
                                                   .Where(predicate) 
              select cp.LogEntry) 
             as ObjectQuery).Include("GameFile").ToList();
    

    工作 ,但是很难看。我们能做得更好吗?

    我可以想出两个办法来解决这个问题。大多数情况下,这取决于是否实际需要返回实体类型。如果没有看到你的其他代码,我不能说这是不是真的。通常,在更新(或修改)实体类型时,需要返回它们。如果选择用于显示或计算目的,则返回poco而不是实体类型通常是更好的策略。你可以这样做 projection

     public IQueryable<ClientInfo> GetConnectedClients()
     {
          return from cp in _context.Clients
                 where // ...
                 select new ClientInfo
                 {
                     Id = cp.Id,
                     ClientName = cp.ClientName,
                     LogEntry = new LogEntryInfo
                                {
                                    LogEntryId = cp.LogEntry.LogEntryId,
                                    GameFile = new GameFileInfo
                                               {
                                                   GameFileId = cp.LogEntry.GameFile.GameFileId,
                                                   // etc.
                                               },
                                    // etc.
                                },
                      // etc.
                 };
     }
    

    请注意,当您使用投影时,没有紧急加载、延迟加载和显式加载。只有你的意图,表达为一个疑问。LINQ提供者会找出你需要什么, 即使您在存储库之外进一步组合查询!

    另一方面,您可能需要返回实体类型而不是poco,因为您打算更新它们。在这种情况下,我将为日志条目编写一个单独的存储库方法,正如Tomas所建议的那样。但是,只有在我打算更新它们的情况下才会这样做,我可能会将其编写为更新方法,而不是“Get”方法。

        3
  •  -1
  •   Tomas Aschan    14 年前

    似乎你还需要一个存储库方法,这将为你做到这一点; _connectedClientsRepository.GetLogEntriesOfConnectedClients()