Problème: Le tri pour GridView / ObjectDataSource change en fonction de la page
-
22-07-2019 - |
Question
J'ai un GridView lié à un ObjectDataSource en utilisant la pagination. La pagination fonctionne correctement, sauf que l'ordre de tri change en fonction de la page d'affichage des résultats. Cela provoque des éléments à réapparaître sur les pages suivantes parmi d'autres problèmes. J'ai tracé le problème dans mon DAL, qui lit une page à la fois puis le trie. De toute évidence, le tri va changer en fonction de la taille du jeu de résultats. Y a-t-il une amélioration à cet algorithme? J'aimerais utiliser un datareader si possible:
[System.ComponentModel.DataObjectMethod(System.ComponentModel.DataObjectMethodType.Select)]
public static WordsCollection LoadForCriteria(string sqlCriteria, int maximumRows, int startRowIndex, string sortExpression)
{
//DEFAULT SORT EXPRESSION
if (string.IsNullOrEmpty(sortExpression)) sortExpression = "OrderBy";
//CREATE THE DYNAMIC SQL TO LOAD OBJECT
StringBuilder selectQuery = new StringBuilder();
selectQuery.Append("SELECT");
if (maximumRows > 0) selectQuery.Append(" TOP " + (startRowIndex + maximumRows).ToString());
selectQuery.Append(" " + Words.GetColumnNames(string.Empty));
selectQuery.Append(" FROM sw_Words");
string whereClause = string.IsNullOrEmpty(sqlCriteria) ? string.Empty : " WHERE " + sqlCriteria;
selectQuery.Append(whereClause);
selectQuery.Append(" ORDER BY " + sortExpression);
Database database = Token.Instance.Database;
DbCommand selectCommand = database.GetSqlStringCommand(selectQuery.ToString());
//EXECUTE THE COMMAND
WordsCollection results = new WordsCollection();
int thisIndex = 0;
int rowCount = 0;
using (IDataReader dr = database.ExecuteReader(selectCommand))
{
while (dr.Read() && ((maximumRows < 1) || (rowCount < maximumRows)))
{
if (thisIndex >= startRowIndex)
{
Words varWords = new Words();
Words.LoadDataReader(varWords, dr);
results.Add(varWords);
rowCount++;
}
thisIndex++;
}
dr.Close();
}
return results;
}
La solution
J'ai trouvé une solution à ce problème en lisant MSDN. L'astuce consiste à effectuer la requête complète et à ne renvoyer que le sous-ensemble intéressant, afin que le tri soit toujours cohérent. La procédure ne fonctionne toutefois qu'avec SQL 2005.
[System.ComponentModel.DataObjectMethod(System.ComponentModel.DataObjectMethodType.Select)]
public static WordsCollection LoadForCriteria(string sqlCriteria, int maximumRows, int startRowIndex, string sortExpression)
{
//DEFAULT SORT EXPRESSION
if (string.IsNullOrEmpty(sortExpression)) sortExpression = "OrderBy";
//CREATE THE DYNAMIC SQL TO LOAD OBJECT
StringBuilder selectQuery = new StringBuilder();
selectQuery.Append("SELECT ");
selectQuery.Append(Words.GetColumnNames(string.Empty));
selectQuery.Append(" FROM (");
selectQuery.Append("SELECT ");
selectQuery.Append(Words.GetColumnNames(string.Empty));
selectQuery.Append(", ROW_NUMBER() OVER (ORDER BY " + sortExpression + ") AS RowRank");
selectQuery.Append(" FROM sw_Words) AS WordsWithRowNumbers");
selectQuery.Append(" WHERE RowRank >" + startRowIndex.ToString() + " AND " + "RowRank <=" + (startRowIndex + maximumRows).ToString());
string whereClause = string.IsNullOrEmpty(sqlCriteria) ? string.Empty : " AND " + sqlCriteria;
selectQuery.Append(whereClause);
Database database = Token.Instance.Database;
DbCommand selectCommand = database.GetSqlStringCommand(selectQuery.ToString());
//EXECUTE THE COMMAND
WordsCollection results = new WordsCollection();
int rowCount = 0;
using (IDataReader dr = database.ExecuteReader(selectCommand))
{
while (dr.Read())
{
Words varWords = new Words();
Words.LoadDataReader(varWords, dr);
results.Add(varWords);
rowCount++;
}
dr.Close();
}
return results;
}