Premesso che non sono esperto in mobile, quest'oggi mi sono messo al lavoro per la prima volta con il SqlServerCe, ho visto che è presente una classe chiamata SqlCeResult set che fornisce operazioni di lettura e scrittura con elevate performance. Dato che in un palmare la memoria è da risparmiare, mi sono subito posto il problema di dire, se io faccio una query che ritorna molti record, mi conviene creare dei business object e aumentare il carico di ram? Non usando i business object non vorrei però andare a prendere i dati direttamente dal SqlCeResult, allora mi sono fatto prima una piccola classe helper statica con un metodo.
public static HelperResultSet ExecuteResultSet(String query, ResultSetOptions options) {
SqlCeConnection connection = new SqlCeConnection(DatabaseConnection);
SqlCeCommand command = new SqlCeCommand();
command.Connection = connection;
command.CommandText = query;
connection.Open();
return new HelperResultSet(command.ExecuteResultSet(options), command, connection);
}
Questo metodo accetta una stringa e le opzioni del resultset, poi crea la connessione, il comando apre la connessione esegue il resultset e torna al chiamante una struttura particolare che si chiama HelperResultSet che implementa IDisposable e che tiene un riferimento ai tre oggetti usati. Nel dispose questa classe effettua il dispose del resultset, del comando e della connessione, in modo da non avere leak. A questo punto ho ad esempio una tabella Product, vorrei poter eseguire una query che torna ad esempio tutti i prodotti e visualizzarli, in questo caso io accedo ai metodi solamente in readonly, allora mi sono fatto una piccola classe helper
public class ProductCursor : IDisposable {
private HelperResultSet result;
public String Code {
get { return mCode; }
}
private String mCode = String.Empty;
public String Description {
get { return mDescription; }
}
private String mDescription = String.Empty;
public ProductCursor(HelperResultSet resultSet) {
this.result = resultSet;
}
public IEnumerable<ProductCursor> Scan() {
while (result.ResultSet.Read()) {
mCode = result.ResultSet.GetString(0).TrimEnd();
mDescription = result.ResultSet.GetString(1);
yield return this;
}
}
public void Dispose() {
result.Dispose();
}
}
In sostanza creo una ProductCursor da un oggetto HelperResultSet visto in precedenza, grazie all'istruzione yield posso usare la classe in un foreach che a tutti gli effetti non crea nuove classi ma aggiorna ad ogni iterazione l'unica istanza dell'oggetto ProductCursor, in questo modo ho un impatto basso sulla memoria, il chiamante lo usa in questo modo.
ProductDao dao = new ProductDao();
ProductCursor cursor = dao.GetAll();
foreach (ProductCursor pc in cursor.Scan()) {
Console.WriteLine(pc.Code);
}
In sostanza si esegue un foreach sul ProductCursor, ma l'oggetto tornato è sempre lo stesso, solo che cambiano le proprietà perché ad ogni iterazione si fa avanzare il SqlCeResultSet di una posizione. Chiaramente in questo modo il ProductCursor offre una scansione readonly, che però è tipizzata e ha un impatto minore sul sistema.
Alk.