L'implementazione di Olivier è buona. Usa generici e interfacce dando a ciascuna entità la propria implementazione di FillFromDataReader().
Si può prendere più lontano. Utilizzando la convenzione, tutti i dati relativi al codice di idratazione possono essere centralizzati e astratti.
Ho intenzione di assumere che i nomi delle proprietà di classe e i nomi delle colonne siano gli stessi. Se non lo sono, è possibile estendere il seguente codice per aggiungere gli attributi alias ai nomi di proprietà. A volte una proprietà viene calcolata da altri valori nell'oggetto, questa proprietà non può essere idratata. Un attributo Ignore può essere creato e implementato nella classe sottostante.
public class DataAccess
{
/// <summary>
/// Hydrates the collection of the type passes in.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sql">The SQL.</param>
/// <param name="connection">The connection.</param>
/// <returns>List{``0}.</returns>
public List<T> List<T>(string sql, string connection) where T: new()
{
List<T> items = new List<T>();
using (SqlCommand command = new SqlCommand(sql, new SqlConnection(connection)))
{
string[] columns = GetColumnsNames<T>();
var reader = command.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
T item = new T();
foreach (var column in columns)
{
object val = reader.GetValue(reader.GetOrdinal(column));
SetValue(item, val, column);
}
items.Add(item);
}
command.Connection.Close();
}
return items;
}
/// <summary>
/// Sets the value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item">The item.</param>
/// <param name="value">The value.</param>
/// <param name="column">The column.</param>
private void SetValue<T>(T item, object value, string column)
{
var property = item.GetType().GetProperty(column);
property.SetValue(item, value, null);
}
/// <summary>
/// Gets the columns names.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>System.String[][].</returns>
private string[] GetColumnsNames<T>() where T : new()
{
T item = new T();
return (from i in item.GetType().GetProperties()
select i.Name).ToArray();
}
}
Ci sono un paio di avvertimenti nel codice sopra. I tipi DBNull e Nullable sono casi speciali e richiedono un codice personalizzato per gestirli. Di solito converto DBNull a null. Non mi sono mai imbattuto in un caso in cui dovevo distinguere il diverso tra i due. Per i tipi Nullalbe, è sufficiente rilevare il tipo Nullable e gestire il codice di conseguenza.
Un ORM rimuoverebbe gran parte del problema relativo alla gestione dell'accesso ai dati. Lo svantaggio è che molte volte si è accoppiati al DTO e allo schema del database. Ovviamente questo problema può essere contenuto usando le astrazioni.Molte aziende usano ancora procedure rigorosamente archiviate, la maggior parte delle ORM cadono quando sono costrette a consumare stored procedure. Non sono progettati per funzionare con le stored procedure.
Ho scritto un quadro di accesso ai dati denominato "Hypersonic". È su GitHub, è specificamente progettato per funzionare con stored procedure. Il codice sopra è una leggera implementazione di esso.
fonte
2013-01-01 19:42:07
Questo è fondamentalmente ciò che fa un ORM. Perché non usare un ORM? Entity Framework funziona piuttosto bene, lo stiamo utilizzando in una grande applicazione LOB con oltre 400 clienti che eseguono un'applicazione SAAS (con almeno 3 computer di cui ciascuno) e il lato server è ospitato nei nostri server. –
Dai uno sguardo a [ValueInjecter] (http://valueinjecter.codeplex.com/) e specialmente a [questo esempio] (http://goo.gl/mD5OG), questo mappa un lettore di dati in un elenco di oggetti di dominio nel modo in cui vuoi farlo. Regardas e felice anno nuovo! – Hugo