Resumé

Populate Business Logic Classes with Reflection

Cristian Merighi () 0.00

How to avoid the ugly, tedious, hard-coded lines written for building up our BLL classes from the usual DataRows? ...using Reflection!
This article is obsolete. Some functionalities might not work anymore. Comments are disabled.

In this article I'll discuss how to use Reflection API's to populate a business logic (BLL) class.

To expose properties in a more elegant (less hard-coded) way, I've been thinking about using Reflection API's and Custom Attributes
The Idea is to bind private/public fields/properties of a BLL class just by assigning - via custom attributes - a binding between the field/property itself and a value stored, let's say, in a DataRow.
Something like...

public class BLLClass : Pacem.Reflection.Accessible
{
    public BLLClass(DataRow r) : base(r){}
    
    [Pacem.Reflection.Field("MyDataBaseColumnName")]
    private string _MyBLLClassPrivateField = string.Empty;
}

In my solution I developed a base abstract (MustInherit) class named "Accessible" which can be instantiated using a Dictionary or... ta-da!... a DataRow!
In its self-building process it parses the fields associated with custom "FieldAttributes", setting the correspondant values stored in the Dictionary/DataRow object.

The key piece of code for building the Accessible subclass is the following:

//... omitted code...
Type myType = this.GetType();
foreach (FieldInfo fInfo in 
    myType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
    foreach (object attr in 
        fInfo.GetCustomAttributes(typeof(Pacem.Reflection.FieldAttribute), true))
    {
        Pacem.Reflection.FieldAttribute field = (Pacem.Reflection.FieldAttribute)attr;
        if (!InnerDictionary.ContainsKey(field.Name)) throw new KeyNotFoundException(string.Format(
            "Pacem: there is no field named '{0}' in the source object.", field.Name));
        object myVal = InnerDictionary[field.Name];
        bool isDBNull = object.Equals(DBNull.Value, myVal);
        try
        {
            if (!isDBNull | (isDBNull & !field.SkipDBNull)) fInfo.SetValue(this, Convert.ChangeType(myVal, fInfo.FieldType));
        }
        catch (Exception e)
        {
            throw new Exception(string.Format("Field [{1}, Value[{2}]]: {0}", e.Message, field.Name, myVal), e);
        }
        
    }
}
//... omitted code...

So, isn't it much cleaner? Combining the Pacem.Reflection.Accessible class and the custom Pacem.Reflection.FieldAttributes there's no more need of ugly code lines like:

public BLLClass(DataRow r){
    this._MyBLLClassPrivateField = r["MyDataBaseColumnName"].ToString();
    if (!r["My2ndDataBaseColumnName"].Equals(DbNull.Value)
    {
        this._My2ndBLLClassPrivateField = Convert.ToInt32(r["My2ndDataBaseColumnName"]);
    }
    // ...and so on :(
}
« download code for this article

Take care. Bye.

Feedbacks

  • Re: Populate Business Logic Classes with Reflection

    Alberto Dallagiacoma Saturday, November 18, 2006 0.00

    Ciao Cristian, se hai delle classi di BLL da popolare, perché non popolarle direttamente dal DAL (ed evitare quindi che il DAL restituisca delle datarow)? Secondo me così facendo si riduce l'accoppiamento classi business-base dati, aumentando la flessibilità. Ok, ok, ci sarebbe da discutere per ore... ;-)

  • Re: Populate Business Logic Classes with Reflection

    CMerighi Saturday, November 18, 2006 0.00

    Puoi aver ragione, io ti porto comunque le mie motivazioni: prima di tutto, per quanto riguarda l'accoppiamento DAL-BLL, penso che la stessa strutturazione del database sia risultato di un'analisi basata sulla logica dell'applicativo e quindi da esso difficilmente disaccoppiabile. Nello sviluppo dello stesso applicativo, limito la DAL ad esporre elementi come <i>DataRow</i>, <i>DataTable</i> e <i>DataSet</i> slegati dal particolare tipo di DB (che può quindi agilmente essere migrato) e manipolabili a piacimento dallo strato Business, un tocco di flessibilità in più viene dalla rimappatura dei nomi delle colonne delle varie tabelle (che slega in toto la BLL dal DB contestuale) e dalle classi statiche "Manager" che predispongo a manipolare i dati provenienti dalla DAL: esse creano le varie collection o classi... e servono gli <i>ObjectDataSource</i> del presentation layer. In secondo luogo, l'esempio riportato in questo articolo s'inserisce in un contesto più ampio in cui sono previste funzionalità di Update ed Insert integrate nella classe base <i>Accessible</i> (utilizzando un DataAdapter "arricchito" e sempre sfruttando Reflection). Mi sto trovando a dover gestire classi con diverse decine(!) di proprietà ed il poterle aggiornare con un comando del tipo "MyBLLClass.Update()" o "MyBLLClass.Insert()" mi è di parecchio conforto! Grazie sinceramente del consiglio comunque... o, come dicono gli anglosassoni, <i>Thank you for asking!</i>

  • Re: Populate Business Logic Classes with Reflection

    Alberto Dallagiacoma Sunday, November 19, 2006 0.00

    Sebbene sembri un po' strano, io generalmente cerco di non pensare ad un applicazione data oriented partendo dalla struttura del db, bensì dalle business entities. Così facendo, gestisco la persistenza come servizio, e le varie funzioni di update, delete, ecc... mi vengono fornite da un data provider specifico (Sql server, Oracle, e così via). Le classi "Manager" chiameranno i metodi del data provider correntemente attivo. Nel tuo caso il leggere una datatable-datarow da db e poi popolare le Business Entities introduce, secondo me, un po' di overhead. Ciao

  • Re: Populate Business Logic Classes with Reflection

    CMerighi Monday, November 20, 2006 0.00

    Ciao Alberto, ti rispondo per punti... 1. ti quoto un attimo... "<i>generalmente cerco di non pensare ad un applicazione data oriented partendo dalla struttura del DB, bensì dalle business entities</i>" ...secondo me stiamo dicendo la stessa cosa: le business entities sono la base dell'applicativo, risultato dell'analisi effettuata a monte sulla quale la stessa struttura del DB si poggia. 2. relativamente alla questione del popolare le classi BLL direttamente dalla DAL e relativo <i>overhead</i>, posso essere d'accordo ma lo stimo minimo (l'overhead): lavoro sempre su un set di risultati al massimo uguale a quelli contenuti in una pagina di gridview (10-20 elementi). Inoltre, se prendi come modello di strutturazione 3-tier quella riportata ad esempio <a href="http://www.asp.net/learn/dataaccess/tutorial02cs.aspx?tabid=63" target="_blank">qui</a>, devo dire che non mi soddisfa: sicuramente mi sbaglio, ed in questo ti prego di darmi conferma o smentita, ma non mi sento in pieno controllo del processo, specie per ciò che riguarda le collection generate. Mi risulta comodo poter, ad esempio, personalizzare ed integrare i filtri sugli elementi di una collection di custom BLL entities utilizzando predicates etc... e ciò non mi è intuitivamente possibile rifacendomi al modello cui, penso, mi rimandi tu. Fammi sapere!...

  • Re: Populate Business Logic Classes with Reflection

    Alberto Dallagiacoma Monday, November 20, 2006 0.00

    Relativamente al punto 1, sono d'accordo con te. :-) Sul punto 2, nel tuo caso (10-20 elementi) l'overhead è sicuramente trascurabile. però trovo molto più "controllabile" una collection scritta ad hoc (derivata da System.Collection.ObjectModel.Collection<T>), piuttosto che un DataSet che magari comprende tante features che poi non vado ad utilizzare. La gestione dei filtri e delle ricerche su una custom collection comporta sicuramente molto più lavoro rispetto ad un DataSet/DataTable, ma con i generics ed i predicates si sono fatti molti passi avanti. Quello che a me piace fare è utilizzare direttamente le business entities come "linguaggio comune" tra i tiers, in modo da avere la presentation che sa come mostrare un "Customer", la BLL che sa cosa si può fare su un "Customer" e il DAL che sa come persistere un "Customer", il tutto senza passare da DataSet. Come ho detto prima, di cui potremmo parlare per ore... Ciao, Alberto

  • Re: Populate Business Logic Classes with Reflection

    CMerighi Tuesday, November 21, 2006 0.00

    ...penso che possiamo ritenerci d'accordo anche sul punto 2(!): per me tutto parte dalla costruzione di Collection di Business Entities (subclassi ad esempio di System.Collection.Generic.List&lt;T&gt;). Tale istanziazione avviene tramite arrays di DataRow, risultato delle query specifiche effettuate sulla DAL, più qualche eventuale filtro a posteriori (vedi metodo <i>Select()</i> della classe <i>DataTable</i>). Sono queste collection a "menare la danza" (a livello presentation non si avrà mai a che fare con un <i>DataSet</i>). Da quello che mi pare di capire la differenza che ci separa riguarda le modalità di popolamento delle Business entities... Mi piacerebbe parlarne, sinceramente, ma farlo attraverso i commenti di un blog secondo me introduce un po' di "overhead"(^_^)! Potrebbe essere davvero interessante condividere e confrontare le nostre opinioni magari a quattr'occhi, visto che anche il geomapping dice che è fattibile ;) Fammi sapere, anche via mail. Grazie. Cristian.

  • Re: Populate Business Logic Classes with Reflection

    Alberto Dallagiacoma Tuesday, November 21, 2006 0.00

    Chiederò a Michela di organizzare un appuntamento... :-)

feedback
 

Syndicate

Author

Cristian Merighi facebook twitter google+ youtube

Latest articles

Top rated

Archive

Where am I?

Author

Cristian Merighi facebook twitter google+ youtube

I'm now reading

Feeds