【问题标题】:Entity Framework Select Items Position In Ordered list实体框架在有序列表中选择项目位置
【发布时间】:2017-04-20 09:09:30
【问题描述】:

我想在有序列表中选择用户的位置。

我只能通过将所有项目加载到内存中然后使用IndexAt() 方法来查找位置来使其工作。但是,当数据库中有很多行时,这并不能很好地工作。

        public static async Task<int> GetUsersRank(DbEntities db, string userId)
    {           
      var items = await db.UserIqAnswers.Where(x => x.IqQuestion.CorrectAnswer == x.Answer).GroupBy(x => x.UserId).Select(x => new { userId = x.Key, points = x.Sum(y => y.IqQuestion.Points) })
         .OrderBy(x => x.points)
         .ToListAsync();
      return items.FindIndex(x => x.userId == userId) + 1;         
    }

我怎样才能更有效地做到这一点?

【问题讨论】:

    标签: c# sql-server entity-framework-6 linq-to-entities


    【解决方案1】:

    这样的? 这将运行两个查询。一个加载当前用户的信息,另一个加载列表中的位置。 不过,查询应该相当有效。第二个应该作为 SQL 服务器端的 COUNT() 来完成。

    var sumByUser = db.UserIqAnswers.Where(x => x.IqQuestion.CorrectAnswer == x.Answer)
        .GroupBy(x => x.UserId)
        .Select(x => new { userId = x.Key, points = x.Sum(y => y.IqQuestion.Points) });
    var currentUser = sumByUser.Where(x => x.userId == userId).Single();
    var rank = sumByUser.Where(x => x.points > currentUser.points).Count();
    

    请注意,“sumByUser”查询永远不会执行,它只是用作接下来两个查询的基础。

    您可以使用 LINQ 语法将其重写为作为一个查询运行:

    (from currentUser in sumByUser.Where(x => x.userId == userId)
     from rank in sumByUser.Where(x => x.points > currentUser.points
     select new { currentUser, rank = rank.Count()}).Single()
    

    但我会检查那个生成的 SQL 以确定。

    【讨论】:

      【解决方案2】:

      answer by gnud 提出了正确的想法,但不幸的是,提供的两种解决方案都不能很好地转换为 SQL。这是因为 EF6 查询翻译仍然对您编写 LINQ 查询的方式很敏感(很遗憾)。

      这是一个实现(通过实验找到),它产生了良好的转换(将 decimal? 强制转换为 Points 属性类型的可空类型 - 如果集合为空,需要强制转换以避免 NRE) :

      public static async Task<int> GetUsersRank(DbEntities db, string userId)
      {
          var userPoints = await db.UserIqAnswers
              .Where(x => x.UserId == userId && x.IqQuestion.CorrectAnswer == x.Answer)
              .SumAsync(x => (decimal?)x.IqQuestion.Points) ?? 0;
      
          var rank = await db.UserIqAnswers
              .Select(x => new { x.UserId, x.Answer, x.IqQuestion })
              .Where(x => x.UserId != userId && x.IqQuestion.CorrectAnswer == x.Answer)
              .GroupBy(x => x.UserId)
              .Select(x => new { userId = x.Key, points = x.Sum(y => y.IqQuestion.Points) })
              .CountAsync(x => x.points < userPoints || (x.points == userPoints && string.Compare(x.userId, userId) < 0));
      
          return rank;
      }
      

      生成 2 个这样的 SQL:

      SELECT
          [GroupBy1].[A1] AS [C1]
          FROM ( SELECT
              SUM([Extent2].[Points]) AS [A1]
              FROM  [dbo].[UserIqAnswers] AS [Extent1]
              INNER JOIN [dbo].[IqQuestions] AS [Extent2] ON ([Extent1].[Answer] = [Extent2].[CorrectAnswer]) AND ([Extent1].[IqQuestion_Id] = [Extent2].[Id])
              WHERE [Extent1].[UserId] = @p__linq__0
          )  AS [GroupBy1]
      

      SELECT
          [GroupBy2].[A1] AS [C1]
          FROM ( SELECT
              COUNT(1) AS [A1]
              FROM ( SELECT
                  [Extent1].[UserId] AS [K1],
                  SUM([Extent2].[Points]) AS [A1]
                  FROM  [dbo].[UserIqAnswers] AS [Extent1]
                  INNER JOIN [dbo].[IqQuestions] AS [Extent2] ON ([Extent1].[IqQuestion_Id] = [Extent2].[Id]) AND ([Extent2].[CorrectAnswer] = [Extent1].[Answer])
                  WHERE [Extent1].[UserId] <> @p__linq__0
                  GROUP BY [Extent1].[UserId]
              )  AS [GroupBy1]
              WHERE ([GroupBy1].[A1] < @p__linq__1) OR (([GroupBy1].[A1] = @p__linq__2) AND ([GroupBy1].[K1] < @p__linq__3))
          )  AS [GroupBy2]
      

      【讨论】:

        【解决方案3】:

        使用Skip:获取元素501 ..

        queryable.Skip(500).Take(1).ToList();
        

        【讨论】:

        • 这不会帮助您找到元素的位置。如果您已经知道所需元素的位置,这只会对您有所帮助。
        • @gnud 你说得对,我向后理解了这个问题。
        猜你喜欢
        • 2013-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-25
        相关资源
        最近更新 更多