如何将行号投射到Linq查询结果中

35
我如何将行号投影到linq查询结果集中?

而不是这样说:

字段1、字段2、字段3

字段1、字段2、字段3

我想要的是:

1、字段1、字段2、字段3

2、字段1、字段2、字段3

以下是我的尝试:

public List<ScoreWithRank> GetHighScoresWithRank(string gameId, int count)
{
    Guid guid = new Guid(gameId);
    using (PPGEntities entities = new PPGEntities())
    {
        int i = 1;
        var query = from s in entities.Scores
                    where s.Game.Id == guid
                    orderby s.PlayerScore descending
                    select new ScoreWithRank()
                    {
                        Rank=i++,
                        PlayerName = s.PlayerName,
                        PlayerScore = s.PlayerScore
                    };
        return query.ToList<ScoreWithRank>();
    }
}

不幸的是,“Rank=i++”这一行会抛出以下编译时异常:

“表达式树可能不包含赋值运算符”


可能是如何将索引字段添加到Linq结果的重复问题。 - Michael Freidgeim
5个回答

56

最简单的方法是在客户端而不是数据库端完成操作,使用提供索引的Select重载方法:

public List<ScoreWithRank> GetHighScoresWithRank(string gameId, int count)
{
    Guid guid = new Guid(gameId);
    using (PPGEntities entities = new PPGEntities())
    {
        var query = from s in entities.Scores
                    where s.Game.Id == guid
                    orderby s.PlayerScore descending
                    select new
                    {
                        PlayerName = s.PlayerName,
                        PlayerScore = s.PlayerScore
                    };

        return query.AsEnumerable() // Client-side from here on
                    .Select((player, index) => new ScoreWithRank()
                            {
                                PlayerName = player.PlayerName,
                                PlayerScore = player.PlayerScore,
                                Rank = index + 1;
                            })
                    .ToList();

    }
}

4
从数据库中获取所有内容并不是一个真正的“解决方案”。 - DATEx2
1
@DotNetWise:它并不是从数据库中获取所有内容 - 只有与查询匹配的部分。它只从数据库中获取与原始尝试相同数量的数据 - 只是进行了一些后处理。 - Jon Skeet
怎么做呢?query.AsEnumerable()会提供给定gameId的所有匹配记录。尝试只取排名在第20名之后的位置。 您将获得数据库中的所有内容,以便获得排名,然后剪切所需内容。不是我们期望的解决方案!除此之外 - count参数用在哪里了? - DATEx2
6
我同意 count 参数尚未使用,但只要在 AsEnumerable() 调用之前使用它就可以。特别是,在 AsEnumerable() 之前使用了 where 子句和 orderby 子句,因此所有的筛选将在数据库中进行。正如我在先前的评论中所说,它只获取与查询匹配的记录... 换句话说,这些数据是必需的。如果你想获取排名第20位之后的职位,你可以向 query 添加一个 Skip 调用,或者使用 query.Skip(20).AsEnumerable()。 (然后您需要调整 Rank 计算。) - Jon Skeet
7
@MikeKulls:所以仅因为LINQ不能处理所有数据库的操作,你就不使用它来处理任何操作吗?这听起来像是把孩子和洗脸水一起倒掉了。 - Jon Skeet
显示剩余2条评论

1

好的,那就解决了。谢谢。

这是我的最终代码...

服务器:

public List<Score> GetHighScores(string gameId, int count)
{
    Guid guid = new Guid(gameId);
    using (PPGEntities entities = new PPGEntities())
    {
        var query = from s in entities.Scores
                    where s.Game.Id == guid
                    orderby s.PlayerScore descending
                    select s;
        return query.ToList<Score>();
    }                                                                      
}

客户:

void hsc_LoadHighScoreCompleted(object sender, GetHighScoreCompletedEventArgs e)
{
    ObservableCollection<Score> list = e.Result;

    _listBox.ItemsSource = list.Select((player, index) => new ScoreWithRank()
                            {
                                PlayerName = player.PlayerName,
                                PlayerScore = player.PlayerScore,
                                Rank = index+=1
                            }).ToList();
}

你真的需要让GetHighScores()返回一个List<Score>而不是一个IEnumerable<Score>吗?如果你要将它转换成列表,那么最好只做一次。 - Jon Skeet
@Jon: 他可以调用AsEnumerable,但是... AsEnumerable方法除了改变源的编译时类型外没有任何效果。换句话说,它不会将对象载入内存。如果他想控制它,ToList就很好。http://msdn.microsoft.com/en-us/library/bb335435.aspx - Amy B
是的,但只有在那个时候他需要这样做。如果他不需要,复制所有数据两次就没有意义了。因此,我的评论是问问题的性质 :) 实际上,即使AsEnumerable也不需要 - 如果GetHighScores方法被声明为返回IEnumerable<Score>,那就可以了。 - Jon Skeet
Rank = index+1 会比 Rank = index += 1 更好,你认为呢? - NetMage

0

你也可以对原始代码进行微小的调整以使其正常工作。需要注意的是,如果你再次绑定数据或访问对象,则排名将每次递增。在这些情况下,最佳答案是使用顶部答案。

let Rank = i++

并且

Rank.ToString()

完整代码:
public List<ScoreWithRank> GetHighScoresWithRank(string gameId, int count)
{
Guid guid = new Guid(gameId);
using (PPGEntities entities = new PPGEntities())
{
    int i = 1;
    var query = from s in entities.Scores
                let Rank = i++
                where s.Game.Id == guid
                orderby s.PlayerScore descending
                select new ScoreWithRank()
                {
                    Rank.ToString(),
                    PlayerName = s.PlayerName,
                    PlayerScore = s.PlayerScore
                };
    return query.ToList<ScoreWithRank>();
}

}


3
这段代码甚至无法编译。它会生成错误 CS0832:表达式树不能包含赋值运算符。 - Ashraf Sabry

0

不支持带有Int32参数的重载实体框架。请注意,dotNetFunda上的文章使用linq to objects。 - Ashraf Sabry

0
List<Emp> Lstemp = GetEmpList(); 
int Srno = 0; 
var columns = from t in Lstemp 
              orderby t.Name 
              select new { 
                  Row_number=++Srno, 
                  EmpID = t.ID, 
                  Name = t.Name, 
                  City = t.City 
              };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接