Oliviers Umsetzung ist gut. Es verwendet Generics und Interfaces, die jeder Entity eine eigene Implementierung von FillFromDataReader() geben.
Sie können es weiter bringen. Durch Verwendung der Konvention kann der gesamte Datenhydrierungscode zentralisiert und abstrahiert werden.
Ich gehe davon aus, dass Ihre Klasseneigenschaftsnamen und Ihre Spaltennamen identisch sind. Wenn dies nicht der Fall ist, kann der folgende Code so erweitert werden, dass den Eigenschaftsnamen Alias-Attribute hinzugefügt werden. Manchmal wird eine Eigenschaft aus anderen Werten im Objekt berechnet, diese Eigenschaft kann nicht hydriert werden. Ein Ignore-Attribut kann in der folgenden Klasse erstellt und implementiert werden.
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();
}
}
Es gibt ein paar Vorbehalte im obigen Code. DBNulls und NULL-Typen sind Sonderfälle und erfordern benutzerdefinierten Code, um mit ihnen umzugehen. Normalerweise konvertiere ich DBNull in null. Ich bin nie auf einen Fall gestoßen, in dem ich den Unterschied zwischen den beiden unterscheiden musste. Für Nullalbe-Typen, erkennen Sie einfach den Nullable-Typ und behandeln den Code entsprechend.
Ein ORM würde viel von dem Kopfschmerz beim Umgang mit Datenzugriff entfernen. Der Nachteil ist, dass Sie oft mit den DTOs und dem Datenbankschema verbunden sind. Natürlich kann dieses Problem durch die Verwendung von Abstraktionen eingedämmt werden.Viele Unternehmen verwenden immer noch streng gespeicherte Prozeduren, die meisten ORMs fallen herunter, wenn sie gezwungen werden, gespeicherte Prozeduren zu verwenden. Sie sind nicht entworfen, um mit gespeicherten Prozeduren zu arbeiten.
Ich schrieb ein Datenzugriffs-Framework namens "Hypersonic." Es ist auf GitHub, es wurde speziell entwickelt, um mit gespeicherten Prozeduren zu arbeiten. Der obige Code ist eine leichte Implementierung des it.
Dies ist im Grunde, was ein ORM tut. Warum nicht ein ORM verwenden? Entity Framework funktioniert ziemlich gut, wir verwenden es in einer großen LOB-Anwendung mit mehr als 400 Kunden, die eine SAAS-Anwendung (mit jeweils mehr als 3 Computern) ausführen, und die Serverseite wird auf unseren Servern gehostet. –
Werfen Sie einen Blick auf [ValueInjecter] (http://valueinjecter.codeplex.com/) und speziell auf [dieses Beispiel] (http://goo.gl/mD5OG), dies ordnet einen Datenleser einer Liste von Domänenobjekten zu so wie du es machen willst. Regardas und ein gutes neues Jahr! – Hugo