Как спроецировать номер строки в результаты запроса Linq

Как я могу проецировать номер строки на набор результатов запроса 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 ++» выдает следующее исключение во время компиляции:

«Дерево выражений не может содержать оператор присваивания»

13.12.2008 10:38:52
Michael Freidgeim 13.07.2016 03:28:25
5 ОТВЕТОВ

Что ж, проще всего было бы сделать это на стороне клиента, а не на стороне базы данных, и использовать перегрузку 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();

    }
}
55
1.10.2014 05:58:44
получить все из базы данных - это на самом деле не «решение»
Adaptabi 27.04.2011 08:42:33
@DotNetWise: он не получает все из базы данных - только тот бит, который соответствует запросу. Он получает только тот же объем данных из базы данных, что и первоначальная попытка - просто немного пост-обработки.
Jon Skeet 27.04.2011 08:52:07
Как же так? query.AsEnumerable () будет кормить все соответствующие записи для данного идентификатора игры. Старайтесь занимать только те позиции, которые заняли 20-е место. Вы получите все из БД, чтобы получить ранги, а затем вырежете то, что вам нужно. Не совсем желаемое решение! Кроме этого - где используется параметр count?
Adaptabi 25.06.2011 08:49:46
@DotNetWise: Я согласен , что countпараметр не используется еще, но до тех пор , как используется , прежде чем на AsEnumerable()звонок, это прекрасно. В частности, whereпредложение и orderbyпредложение используются ранее AsEnumerable, поэтому вся эта фильтрация будет выполняться в базе данных. Как я сказал в своем предыдущем комментарии, он получает только те записи, которые соответствуют запросу ... другими словами, данные, которые в любом случае требуются. Если вы хотите, чтобы позиции заняли 20-е место, вы должны добавить Skipвызов queryили использовать query.Skip(20).AsEnumerable(). (Затем вы захотите скорректировать Rankрасчет.)
Jon Skeet 25.06.2011 09:32:34
@MikeKulls: Просто потому, что вы не можете делать все с базами данных с помощью LINQ, вы ничего не делаете ? Это звучит как выбросить ребенка с водой для меня.
Jon Skeet 7.12.2011 22:18:16

Хорошо, это добилось цели. Спасибо.

Вот мой окончательный код ...

Сервер:

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();
}
1
13.12.2008 12:09:37
Вам действительно нужно, чтобы GetHighScores () возвратил List <Score> вместо IEnumerable <Score>? Если вы собираетесь преобразовать его в список, вы можете сделать это только один раз.
Jon Skeet 13.12.2008 12:17:20
@Jon: Вместо этого он мог бы вызвать AsEnumerable, но ... Метод AsEnumerable не имеет никакого другого эффекта, кроме как изменить тип источника во время компиляции. msdn.microsoft.com/en-us/library/bb335435.aspx - другими словами, это не принесет объекты в память. Если он хочет контролировать это, ToList хорош
Amy B 13.12.2008 14:24:16
Да, но только если ему нужно сделать это в этот момент. Если ему не нужно, нет смысла копировать все данные дважды. Отсюда и вопрос природы моего предложения :) На самом деле, конечно, даже AsEnumerable не нужен - если объявлен метод GetHighScores, возвращающий IEnumerable <Score>, который это сделает.
Jon Skeet 13.12.2008 14:29:16
Не было Rank = index += 1бы лучше, как Rank = index+1?
NetMage 23.06.2017 20:21:42

Вы также можете сделать небольшую корректировку исходного кода, чтобы он заработал. Предостережение: если вы снова привязываете данные или получаете доступ к объекту, ранг будет увеличиваться каждый раз. В этих случаях лучший ответ лучше.

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

}

0
3.02.2012 20:40:59
Этот код даже не скомпилируется. Он генерирует ошибку CS0832: Дерево выражений может не содержать оператора присваивания
Ashraf Sabry 10.12.2013 09:10:55

Это решение сработало для меня. http://www.dotnetfunda.com/articles/article1995-rownumber-simulation-in-linq.aspx

.Select((x, index) => new
{
     SequentialNumber = index + 1
    ,FieldFoo = x.FieldFoo                        
}).ToList();
0
3.02.2013 12:56:14
Перегрузка, которая принимает параметр Int32, не поддерживается структурой объекта. Обратите внимание, что статья в dotNetFunda работает с linq для объектов.
Ashraf Sabry 10.12.2013 09:07:20
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 
              };
0
10.06.2019 15:57:59