Mapping Composite Object using Reflection and ValueInjecter

1.1k Views Asked by At

Maybe this question, always asked in this forum, but I don't find the one that I need. My problem is I have a composite class like this

class Customer
{
   private int Id { set; get; } 
   private int Name { set; get; }
   private Company Company { set; get; }
   ...
}

class Company
{
   private int Id { set; get; }
   private string Name { set; get; }
   ...
}

When I get customer data

string sql = "SELECT cust.id, cust.name, comp.name AS [CompanyName] FROM Customer cust INNER JOIN Company comp ON cust.Company = comp.Id";
....
using (IDataReader dr = db.ExecuteReader(cmd))
{
    if (dr.Read())
    {
        customer = (Customer)FillDataRecord(dr, customer);
    }
}

and mapping it to Customer class (Object) using reflection, the code:

public static Object FillDataRecord(IDataRecord dr, Object obj)
{
    try
    {
        Type type = obj.GetType();
        PropertyInfo[] properties = type.GetProperties();

        for (int i = 0; i < dr.FieldCount; i++)
        {
            if (!dr[i].ToString().Equals(string.Empty))
            {
                type.GetProperty(dr.GetName(i)).SetValue(obj, dr[i], null);
            }
        }

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

When its mapping the CompanyName it will return error "Object reference not set to an instance of an object". I've debug and I know the problem, but until now, I cannot solve it.

I know about AutoMapper or Dapper but when I apply to this case I've got the same problem too.

Now I'm using ValueInjecter, from what I've read it can solve my problem. But I've got cust.Id value same with cust.Company.Id and cust.Name = "" and cust.Company.Name = ""

string sql = "select cust.id, cust.name, comp.name from customer cust inner join company comp on cust.company = comp.id";

while (dr.Read())
{
   var cust = new Customer();
   cust.InjectFrom<ReaderInjection>(dr);

   cust.Company = new Company();
   cust.Company.InjectFrom<ReaderInjection>(dr);

   list.add(cust);
}

Is there anything wrong? Please help me.

1

There are 1 best solutions below

6
On

Why are you using Object? Why not make it generic? Like so:

public static T FillDataRecord<T>(IDataRecord dr) where T : new()
{
    T returnedInstance = new T();
    string fieldName = default(string);

    try
    {
        PropertyInfo[] properties = typeof(T).GetProperties();

        fieldName = dr.GetName(i);

        foreach (PropertyInfo property in properties)
        {
            if (property.Name == fieldName)
            {
                // Handle the DBNull conversion issue..
                if (dr.GetValue(i) == DBNull.Value)
                    property.SetValue(returnedInstance, null, null);
                else
                    property.SetValue(returnedInstance, dr[i], null);
            }
        }

        return returnedInstance;
    }
    catch (Exception ex)
    {
        // Handle exception here
    }
}

Then you can do this:

Customer _customer = FillDataRecord<Customer>(dr);

Or, this:

CustomerDetails _customerDetails = FillDataRecord<CustomerDetails>(dr);

In answer to your question.. if theres a possibility of pulling NULL from the database.. you have to check for it.