Sony Arouje

a programmer's log

.NET Reflection–Helpful Functions

leave a comment »

In this post I will explain few functions I created to solve some of the scenarios in one of my project.

Property Defaulter

In one of my project I had to deal with a table that have hundreds of fields but we are dealing with very few field in the table. The several fields of the table needs default values either zero or empty. I know if I am not finding a generic solution I will be in trouble as I had to fill all the fields my self and I don’t want to do that. So I created a small function that will do the job of setting my entities to default values if the properties doesn’t have any values. Here is my function

public static void SetDefaultValue<TEntity>(TEntity entity) where TEntity : class
{
    try
    {
        PropertyInfo[] properties = typeof(TEntity).GetProperties();
        bool isSetDefaultVal = false;
        foreach (PropertyInfo property in properties)
        {
            object propertyValue;
            if (property.CanRead)
            {
                isSetDefaultVal = false;
                if (property.PropertyType.Name != "String" && 
                    property.PropertyType.Name != "Single" && 
                    property.PropertyType.Name != "Int32")
                    continue;
                try
                {
                    propertyValue = property.GetValue(entity, null);
                }
                catch (Exception ex)
                {
                    //log error
                    continue;
                }
                if (propertyValue==null)
                {
                    if (property.PropertyType.Name == "String")
                        propertyValue = "";
                    else
                        propertyValue = 0;

                    isSetDefaultVal = true;
                }
                //set the value if property value is null and set to 0 in above if block.
                if (property.CanWrite && isSetDefaultVal == true)
                {
                    if (property.PropertyType.Name == "Single")
                        property.SetValue(entity, Convert.ToSingle(propertyValue), null);
                    else if (property.PropertyType.Name == "Int32")
                        property.SetValue(entity, Convert.ToInt32(propertyValue), null);
                    else if (property.PropertyType.Name == "String")
                        property.SetValue(entity, "", null);
                }
            }

        }
    }
    catch (Exception ex)
    {
        throw;
    }
}

 

So how we use it, lets see with a e.g

PropertyDefaulter.SetDefaultValue<ItemMaster>(itemMaster);

The above function will inspect the properties in the itemMaster object, if any property doesn’t has value then based on the type the function will set the value. Int or float property will set to 0 and string property will set to empty.

Copy DataReader to Entities

When I was dealing with ADO.NET I used to fetch data from database table using SqlCommand’s execute reader and get the data in DataReader. I have DTO’s (Data Transfer Object) to transfer data between layers. So I have to copy all the data in DataReader to my DTO’s. I need to find an easy way rather than manually assigning values from datareader to properties. Here is my method to do the copy of data from DataReader to my DTO’s

public static List<TEntity> CopyDataReaderToEntity<TEntity>(IDataReader dataReader) 
    where TEntity : class
{
    List<TEntity> entities = new List<TEntity>();
    PropertyInfo[] properties = typeof(TEntity).GetProperties();
    while (dataReader.Read())
    {
        TEntity tempEntity = Activator.CreateInstance<TEntity>();
        foreach (PropertyInfo property in properties)
        {
            SetValue<TEntity>(property, tempEntity, dataReader[property.Name]);
        }
        entities.Add(tempEntity);
    }
    return entities;
}

public static TEntity SetValue<TEntity>(PropertyInfo property, TEntity entity, object propertyValue) 
       where TEntity : class
{
    if (property.CanRead)
    {
        if (property.PropertyType.Name != "String" &&
            property.PropertyType.Name != "Single" && 
            property.PropertyType.Name != "Int32")
            return entity;

        if (propertyValue == null)
        {
            if (property.PropertyType.Name == "String")
                propertyValue = "";
            else
                propertyValue = 0;
        }
        if (property.CanWrite)
        {
            if (property.PropertyType.Name == "Single")
                property.SetValue(entity, Convert.ToSingle(propertyValue), null);
            else if (property.PropertyType.Name == "Int32")
                property.SetValue(entity, Convert.ToInt32(propertyValue), null);
            else if (property.PropertyType.Name == "String")
                property.SetValue(entity, propertyValue, null);
        }
    }
    return entity;
}

 

Here we need to follow a convention to get it working. The convention I follow here is, the Property name in the DTO and the table field should be same.

Let’s see how we can use it.

SqlCommand cmd = new SqlCommand(qryToExecute, connection);
SqlDataReader reader = cmd.ExecuteReader();
List<ItemDetails> itemDetails = SQLHelper.CopyDataReaderToEntity<ItemDetails>(reader);

Create Select and Insert SQL statement Dynamically

When I was dealing with some table that have a lot of fields, I always have trouble in creating select or insert statement. So I created a small function that creates the Select and Insert statement dynamically. Here also I follow the same convention I explained earlier, that is the field name and the property name should be same.

private static List<FiledAndValueHolder> CreateFieldValueMapper<TEntity>(TEntity entity) 
    where TEntity : class
{
    List<FiledAndValueHolder> filedAndValues = new List<FiledAndValueHolder>();
    PropertyInfo[] properties = typeof(TEntity).GetProperties();
    foreach (PropertyInfo property in properties)
    {
        object propertyValue;
        string propertyName;

        if (property.CanRead)
        {
            if (property.PropertyType.Name != "String" &&
                property.PropertyType.Name != "Single" && 
                property.PropertyType.Name != "Int32")
                continue;

            propertyValue = property.GetValue(entity, null);
            propertyName = property.Name;

            if (propertyName.StartsWith("Native"))
                continue;
            FiledAndValueHolder fieldAndValue = new FiledAndValueHolder();
            fieldAndValue.FieldValue = propertyValue;
            fieldAndValue.FiledName = propertyName;
            fieldAndValue.FieldType = property.PropertyType.Name;
            filedAndValues.Add(fieldAndValue);
        }
    }
    return filedAndValues;
}

public static string CreateInsertStatement<TEntity>(TEntity entity, string tableName) 
   where TEntity : class
{
    List<FiledAndValueHolder> filedAndValues = CreateFieldValueMapper<TEntity>(entity);
    string sql = "insert into [dbo]." + tableName + "({0}) values ({1})";
    StringBuilder fieldBuilder = new StringBuilder();
    StringBuilder valueBuilder = new StringBuilder();
    string seprator = string.Empty;
    foreach (FiledAndValueHolder filedAndValue in filedAndValues)
    {
        fieldBuilder.Append(seprator);
        fieldBuilder.Append(filedAndValue.FiledName);

        valueBuilder.Append(seprator);
        if (filedAndValue.FieldType == "String")
        {
            valueBuilder.Append(string.Format("'{0}'", filedAndValue.FieldValue as string));
        }
        else
        {
            valueBuilder.Append(filedAndValue.FieldValue);
        }

        if (string.IsNullOrEmpty(seprator))
            seprator = ",";
    }

    string sqlStatement = string.Format(sql, fieldBuilder.ToString(), valueBuilder.ToString());
    return sqlStatement;
}
public static string CreateSelectStatement<TEntity>(TEntity entity, string tableName, string selectCondition) where TEntity : class
{
    List<FiledAndValueHolder> filedAndValues = CreateFieldValueMapper<TEntity>(entity);
    string sql = "select {0} from dbo.{1} where ({2})";
    StringBuilder fieldBuilder = new StringBuilder();
    string seprator = string.Empty;
    foreach (FiledAndValueHolder filedAndValue in filedAndValues)
    {
        fieldBuilder.Append(seprator);
        fieldBuilder.Append(filedAndValue.FiledName);
        if (string.IsNullOrEmpty(seprator))
            seprator = ",";
    }

    return string.Format(sql, fieldBuilder.ToString(), tableName, selectCondition);
}

 

Let’s see how we can use it.

insertItemMaster = SQLHelper.CreateInsertStatement<ItemMaster>(itemMaster, "ItemMaster");

Most of the functions I explained above doesn’t required much explanations. If any one need any more details then leme know.

Advertisements

Written by Sony Arouje

January 22, 2011 at 1:31 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: