Visst skulle jag kunna det det är dock en hel del. Du behöver en del Attribute klasser och sedan en DataManager och sedan en DataAccess. Du behöver också en BaseCollection-class.
Oberoendet från DBMS kan lösas med hjälp av Interfacen istället för SqlDataReader/OleDbReader kan man använda sig av IDataReader. Professional ADO.NET från wrox har ett kapitel om hur de löser en DataAccess klass som är oberoende av DBMS.
Här kommer lite kod hur du kan lösa det med en LoadData() funktion i en DataManager. Nu visar jag endast hur du kan fylla ett singel objekt med en StoreProcedur.
Attribute för StoreProcedure namnet:
using System;
namespace Test
{
/// <summary>
/// Summary description for SqlParameterLoadAttribute.
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class StoreProcedureAttribute : Attribute
{
#region public methods ---------------------------------------------------------------------------------
public StoreProcedureAttribute(){}
#endregion
}
}
Attribute för databasfältet:
using System;
namespace Test
{
/// <summary>
/// Summary description for SqlParameterLoadAttribute.
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class DatabasFieldAttribute : Attribute
{
#region variables --------------------------------------------------------------------------------------
private string m_DatabasFieldName;
#endregion
#region property ---------------------------------------------------------------------------------------
public string FieldName{
get{return m_DatabasFieldName;}
}
#endregion
#region public methods ---------------------------------------------------------------------------------
public DatabasFieldAttribute(string sDatabasFieldName){
m_DatabasFieldName = sDatabasFieldName;
}
#endregion
}
}
Sedan kod för ditt objekt där du sätter attributen StoreProcedure och Databasfield på members:
using System;
using System.Data.SqlTypes;
namespace Test
{
/// <summary>
/// Summary description for COrder.
/// </summary>
public class COrder : BaseClass
{
#region variables --------------------------------------------------------------------------------------
[StoreProcedure()]
private string m_StoreProcedureName
[DatabasField("UsedFromTurn")]
private int m_UsedFromTurn;
[DatabasField("OrderName")]
private string m_OrderName;
#endregion
#region property ---------------------------------------------------------------------------------------
public int UsedFromTurn{
get{return m_UsedFromTurn;}
set{m_UsedFromTurn = value;}
}
public string OrderName{
get{return m_OrderName;}
set{m_OrderName = value;}
}
#endregion
#region constructors -----------------------------------------------------------------------------------
private COrder(){}
public COrder(string storeProcedureName){
m_StoreProcedureName = storeProcedureName;
}
#endregion
}
}
Och sedan sist DataManger klassen, här har jag plockat bort en del kod eftersom vårt exempel inte använder sig av all kod som jag har i min klass. Det finns dock methoder för att skapa SqlParameters, läsa SqlParameters, spara data...
using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Reflection;
namespace Test
{
/// <summary>
/// Summary description for DataManager.
/// </summary>
public sealed class DataManager
{
#region constructors -----------------------------------------------------------------------------------
private DataManager(){}
#endregion
#region private methods --------------------------------------------------------------------------------
private static void BindDataToObject(object oObject, SqlDataReader oDataReader){
//-- get all fields for this object
foreach (FieldInfo fieldInfo in oObject.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField | BindingFlags.Default))
{
//-- check every field if they have a Attribute named 'DatabasFieldAttribute' and set the value to this field
if(Attribute.IsDefined(fieldInfo, typeof(DatabasFieldAttribute), true))
{
string sFieldName = ((DatabasFieldAttribute)fieldInfo.GetCustomAttributes(typeof(DatabasFieldAttribute),false)[0]).FieldName;
fieldInfo.SetValue(oObject, oDataReader[sFieldName]);
}
}
}
private static string GetStoreProcedureName(object oObject){
//-- get all fields for this object
foreach (FieldInfo fieldInfo in oObject.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField | BindingFlags.Default)){
//-- check every field if they have a Attribute named 'StoreProcedureAttributes'.
if(Attribute.IsDefined(fieldInfo, typeof(StoreProcedureAttribute), true))
return fieldInfo.GetValue(oObject).ToString();
}
throw new Exception("Can't find any field with information about StoreProcedureName");
}
#endregion
#region public methods ---------------------------------------------------------------------------------
public static void LoadData(object oObject){
//-- declare variables
SqlDataReader oDataReader = null;
string sStoreProcedureName = GetStoreProcedureName(oObject);
SqlCommand oSqlCommand = new SqlCommand();
//-- init commandobject
oSqlCommand.CommandType = CommandType.StoredProcedure;
oSqlCommand.CommandText = sStoreProcedureName;
//-- create parameters for this object
CreateSqlParameters(oSqlCommand, oObject, StoreProcedureAction.Load);
try{
//-- Read data from databas
oDataReader = DataAccess.DataAccess.ExecuteReader(oSqlCommand);
//-- bind data to object
while(oDataReader.Read())
BindDataToObject(oObject, oDataReader);
}
catch(Exception exception){
throw new Exception("Error", exception);
}finally{
//-- close reader
if(oDataReader != null)
oDataReader.Close();
}
}
public static void LoadData(BaseCollection oObject){
//-- declare variables
Type tItemType = ((ItemObjectTypeAttribute) oObject.GetType().GetCustomAttributes(typeof(ItemObjectTypeAttribute),true)[0]).Type;
string sStoreProcedureName = GetStoreProcedureName(oObject);
SqlDataReader oDataReader = null;
SqlCommand oSqlCommand = new SqlCommand();
//-- init commandobject
oSqlCommand.CommandType = CommandType.StoredProcedure;
oSqlCommand.CommandText = sStoreProcedureName;
//-- create parameters for this object
CreateSqlParameters(oSqlCommand, oObject, StoreProcedureAction.Load);
try{
//-- Read data from databas
oDataReader = DataAccess.DataAccess.ExecuteReader(oSqlCommand);
while(oDataReader.Read()){
object tmpObject = Activator.CreateInstance(tItemType, true);
BindDataToObject(tmpObject, oDataReader);
oObject.Add(tmpObject);
}
}catch(Exception exception){
throw new Exception("Error", exception);
}finally{
//-- close reader
if(oDataReader != null)
oDataReader.Close();
}
}
#endregion
}
}
Det fungerar så här. Först skapar man sig egna Attributeklasser som du sätter på dina fält/funktioner/klasser. Dessa Attribute definerar om ett fält skall fyllas med värde från databasen och vad fältet i databasen heter: [DatabasField("ID")]
Samma fungerar för Attributet StoreProcedure, fast här har jag valt att man kan skicka in detta från mitt affärslager så jag kan kalla på olika SP om jag vill detta. Man kan lika gärna skriva in Namnet på SP som man gör med Databasfältet, men då kan man endast ha en SP till sin klass.
Sedan i objektet så definerar man sina fält och sätter de Attribute på fältet som man vill ha, du kan ha många Attribute på ett fält, ibland samma Attribute (måste dock skapas med AllowMultiple = True).
Sedan kommer vi till DataManager. Här finns nu LoadData(object oObject) vilket fyller ett objekt, och LoadData(BaseCollection oObject) som fyller ett CollectionObject.
I LoadData så börjar jag med att hämta Namnet på SP och jag vet att jag skall leta efter ett fält som har Attributet [StoreProcedureNamn] och när jag har hittat det fältet (loopar igenom alla fält för klassen) så hämtar jag värdet i det fältet med GetValue().
Sedan så skapar jag en massa Parameters (vilket inte visas här) sedan hämtar jag en DataReader från min DataAccess-klass som har hand om alla DataAccess. Detta DataReader object använder jag när jag sedan skall fylla mitt objekt med data.
I DataBindToObject() så loopar jag igenom alla fält som klassen har och kollar om de har attributet [DatabasField()] definerad, om det har det, så hämtar jag ut värdet från dataReadern och sätter detta till mitt fält med SetValue().
Det är en start, läs på om Attributes och testa dig fram med funktionen GetType() som finns till alla objekt, så hittar du massor med smått och gott.
- M