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

Posted

技术标签:

【中文标题】如何将行号投影到 Linq 查询结果中【英文标题】:How To Project a Line Number Into Linq Query Results 【发布时间】:2010-09-26 18:39:06 【问题描述】:

如何将行号投影到 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++”行会引发以下编译时异常:

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

【问题讨论】:

How do you add an index field to Linq results的可能重复 【参考方案1】:

嗯,最简单的方法是在客户端而不是数据库端执行此操作,并使用 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();

    

【讨论】:

从数据库中获取所有内容并不是真正的“解决方案” @DotNetWise:它没有从数据库中获取 everything - 只有与查询匹配的位。它只是从数据库中获取与最初尝试相同数量的数据 - 只是做了一点后处理。 怎么样? query.AsEnumerable() 将为给定的 gameId 提供所有匹配的记录。尽量只占据排名在第 20 位之后的位置。您将从数据库中获取所有内容以获得排名,然后删除您需要的内容。不是真正想要的解决方案!除此之外 - count 参数在哪里使用? @DotNetWise:我同意count 参数尚未被使用,但只要在AsEnumerable() 调用之前 使用它就可以了。特别是,where 子句和orderby 子句在AsEnumerable 之前使用,因此所有过滤都将在数据库中进行。正如我在之前的评论中所说,它只获取与查询匹配的记录......换句话说,无论如何都需要数据。如果您想获得排在第 20 位之后的位置,您可以向query 添加Skip 调用,或使用query.Skip(20).AsEnumerable()。 (然后您需要调整 Rank 计算。) @MikeKulls:所以仅仅因为你不能用 LINQ 做所有数据库的东西,你就没有做吗?对我来说,这听起来像是把婴儿和洗澡水一起扔出去。【参考方案2】:

好的,成功了。谢谢。

这是我的最终代码...

服务器:

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 而不是 IEnumerable?如果你要把它转换成一个列表,你最好只做一次。 @Jon:他可以调用 AsEnumerable 但是...... AsEnumerable 方法除了更改源的编译时类型之外没有任何作用。 msdn.microsoft.com/en-us/library/bb335435.aspx - 换句话说,它不会将对象带入内存。如果他想控制它,ToList 很好 是的,但只有如果他此时需要这样做。如果他不需要,将所有数据复制两次是没有意义的。因此,我的 cooment 的问题性质 :) 事实上,当然也不需要 AsEnumerable - 如果声明 GetHighScores 方法返回 IEnumerable 就可以了。 Rank = index += 1 会不会比Rank = index+1 更好?【参考方案3】:

您也可以对原始代码稍作调整以使其正常工作。请注意,如果您再次数据绑定或访问该对象,Rank 将每次递增。在这些情况下,最佳答案更好。

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>();

【讨论】:

这段代码甚至无法编译。它会生成错误 CS0832:表达式树可能不包含赋值运算符【参考方案4】:

这个解决方案对我有用。 http://www.dotnetfunda.com/articles/article1995-rownumber-simulation-in-linq.aspx

.Select((x, index) => new

     SequentialNumber = index + 1
    ,FieldFoo = x.FieldFoo                        
).ToList();

【讨论】:

实体框架不支持采用 Int32 参数的重载。请注意,dotNetFunda 上的文章使用 linq to objects。【参考方案5】:
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 
              ;

【讨论】:

以上是关于如何将行号投影到 Linq 查询结果中的主要内容,如果未能解决你的问题,请参考以下文章

LINQ查询表达式 - LINQ 查询分组

java调用栈中行号

java调用栈中行号

java调用栈中行号

Linux命令——nl

linux常用命令nl命令