Problema: l'ordinamento per GridView / ObjectDataSource cambia in base alla pagina
-
22-07-2019 - |
Domanda
Ho un GridView collegato a un ObjectDataSource usando il paging. Il paging funziona correttamente, tranne per il fatto che l'ordinamento cambia in base alla pagina dei risultati visualizzata. Questo fa sì che gli articoli riappaiano nelle pagine successive tra gli altri problemi. Ho rintracciato il problema nel mio DAL, che legge una pagina alla volta e poi la ordina. Ovviamente l'ordinamento cambierà quando cambiano le dimensioni del set di risultati. C'è un miglioramento a questo algoritmo. Vorrei usare un datareader se possibile:
[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;
}
Soluzione
Ho trovato una soluzione a questo problema leggendo MSDN. Il trucco è eseguire la query completa e restituire solo il sottoinsieme interessante in questo modo l'ordinamento è sempre coerente. La procedura, tuttavia, funziona solo con 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;
}