Simple Object Relation Mapping with Reflection

This is some code I wrote a little while back as an example OR mapper.  When inheriting from BaseDataDynamicEntity you can use the attribute [DataDynamic(“Name”)] to indicate the field name in the database and then use the class below to fetch data from the database or update it with any changes.

This is just an example though and doesn't do the updating – but instead returns an array of string that can be used to look at what's in the object now.  Return a set of SqlParameter's and plug it into a stored procedure for a working example.


public abstract class BaseDataDynamicEntity
{
    /// <summary>
    /// An attribute to use to work out which properties have names that are in the database
    /// </summary>
    public class DataDynamic : Attribute
    {
        public DataDynamic(string fieldName)
        {
            _fieldName = fieldName;
        }
        /// <summary>
        /// The name of the field in the database
        /// </summary>
        public string FieldName
        {
            get
            {
                return _fieldName;
            }
        }
        private string _fieldName = "";
    }

    /// <summary>
    /// Return a set of properties on this class as a demonstration of what is possible
    /// </summary>
    /// <returns></returns>
    public string[] ListDataProperties()
    {
        Type t = this.GetType();
        PropertyInfo[] p = t.GetProperties();
        ArrayList properties = new ArrayList();
        foreach (PropertyInfo pi in p)
        {
            if (pi.IsDefined(typeof(DataDynamic), true))
            {
                properties.Add(pi.Name+": "+pi.GetValue(this, null).ToString()); //could instead write these out to some parameters.
            }
        }
        string[] values = new string[properties.Count];
        properties.CopyTo(values);
        return values;
    }

    /// <summary>
    /// Given an SqlDataReader from ExecuteReader, fetch a set of data and use it to fill the child objects properties
    /// </summary>
    /// <param name="dr"></param>
    public void SetDataProperties(SqlDataReader dr)
    {
        while (dr.Read())
        {
            for (int i = 0; i<dr.FieldCount; i++)
            {
                setProperty(dr.GetName(i), dr.GetValue(i));
            }
        }
        dr.Close();
    }

    private void setProperty(string name, object data)
    {
        Type t = this.GetType();
        PropertyInfo[] p = t.GetProperties();
        foreach (PropertyInfo pi in p)
        {
            if (pi.IsDefined(typeof(DataDynamic), true)&&pi.CanWrite)
            {
                object[] fields = pi.GetCustomAttributes(typeof(DataDynamic), true);
                foreach (DataDynamic d in fields)
                {
                    if (d.FieldName == name)
                    {
                        pi.SetValue(this, data, null);
                    }
                }
                           
            }
        }
    }
}

And to use this, you do something like:

public class NewsArticle: BaseDataDynamicEntity
{
    private int _id = 5;
    /// <summary>
    /// The Id in the database
    /// </summary>
    [DataDynamic("id")]
    public int Id
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
        }
    }

    private string _name = "Demo object";
    /// <summary>
    /// The name in the database
    /// </summary>
    [DataDynamic("subject")]
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
        }
    }
}

Which makes populating it as easy as:

SqlConnection sq = new SqlConnection("Data Source=(local);InitialCatalog=nullifydb;Integrated Security=SSPI;");
sq.Open();
SqlCommand sc = sq.CreateCommand();
sc.CommandText = "SELECT TOP 1 * FROM newsarticle";
NewsArticle n = new NewsArticle();
n.SetDataProperties(sc.ExecuteReader());
sq.Close()

Obviously this is just an example, and you would want to use a DAL of some sort to do the data extraction, but integrating the DAL with the above technique should be fairly easy.

You might also like...

Comments

Simon Soanes

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.” - Rich Cook