2

I want to somehow map entity object to business object using reflection in c# -

public class Category
    {
        public int CategoryID { get; set; }
        public string CategoryName { get; set; }
    }

My Entity Class has same properties, CategoryId and CategoryName.Any best practice using reflection or dynamic would be appreciated.

Vishal
  • 12,133
  • 17
  • 82
  • 128
Hidsman
  • 117
  • 1
  • 4
  • 12

4 Answers4

16

You can use Automapper or Valueinjecter

Edit:

Ok I wrote a function that uses reflection, beware it is not gonna handle cases where mapped properties aren't exactly equal e.g IList won't map with List

public static void MapObjects(object source, object destination)
{
    Type sourcetype = source.GetType();
    Type destinationtype = destination.GetType();

    var sourceProperties = sourcetype.GetProperties();
    var destionationProperties = destinationtype.GetProperties();

    var commonproperties = from sp in sourceProperties
                           join dp in destionationProperties on new {sp.Name, sp.PropertyType} equals
                               new {dp.Name, dp.PropertyType}
                           select new {sp, dp};

    foreach (var match in commonproperties)
    {
        match.dp.SetValue(destination, match.sp.GetValue(source, null), null);                   
    }            
}
Serguzest
  • 1,287
  • 10
  • 18
  • i dont want to use any third party or open source – Hidsman Mar 08 '11 at 17:22
  • string destinationPropertyName = LookupMapping(sourceType.ToString(),destinationType.ToString(),sourceProperty.Name ) ; Here LookupMapping is Microsoft Dynamic CRM Function. how i can do it without CRM – Hidsman Mar 08 '11 at 18:15
  • i need to use reflection to avoid fix number of properties. – Hidsman Mar 08 '11 at 21:46
  • I wonder what makes you think it doesn't use reflection? GetValue, SetValue those are reflection methods. – Serguzest Mar 09 '11 at 10:58
  • @Aaabb Bbaa with Valueinjecter you would do a.InjectFrom(b) and that's it – Omu Mar 09 '11 at 21:17
  • 1
    I recently started working on a new project and found a copied version of this code in it. I would strongly recommend using AutoMapper or ValueInjecter as @Serguzest initially suggested as this piece of code created problems in our applications. For example, a List would be null in the destination. – Michael Feb 22 '12 at 18:16
  • Tried your solution (in VB.NET but it's the same). I've added "If match.dp.CanWrite Then" in the foreach cycle. Destination property could not have a setter. I also changed the method signature in this way to make the method more typed: "Public Shared Sub MapObjects(Of T, S)(source As T, destination As S)". Hope it helps. – GiveEmTheBoot Jul 08 '14 at 12:14
0

This is something that I wrote to do what I think you are trying to do and you don't have to cast your business objects:

public static TEntity ConvertObjectToEntity<TEntity>(object objectToConvert, TEntity entity) where TEntity : class
    {
        if (objectToConvert == null || entity == null)
        {
            return null;
        }

        Type BusinessObjectType = entity.GetType();
        PropertyInfo[] BusinessPropList = BusinessObjectType.GetProperties();

        Type EntityObjectType = objectToConvert.GetType();
        PropertyInfo[] EntityPropList = EntityObjectType.GetProperties();

        foreach (PropertyInfo businessPropInfo in BusinessPropList)
        {
            foreach (PropertyInfo entityPropInfo in EntityPropList)
            {
                if (entityPropInfo.Name == businessPropInfo.Name && !entityPropInfo.GetGetMethod().IsVirtual && !businessPropInfo.GetGetMethod().IsVirtual)
                {
                    businessPropInfo.SetValue(entity, entityPropInfo.GetValue(objectToConvert, null), null);
                    break;
                }
            }
        }

        return entity;
    }

Usage example:

public static Category GetCategory(int id)
    {
        return ConvertObjectToEntity(Database.GetCategoryEntity(id), new Category());
    }
Gaff
  • 5,507
  • 3
  • 38
  • 49
0

http://automapper.codeplex.com/

My vote is for auto mapper. I currently use this. I've done performance tests on it, and although it is not as fast as hand mapping (below):

Category c = new Category 
  {
    id = entity.id,
    name = entity.name
  };

The trade off for mapping automatically makes it an obvious choice, at least for the entity to business layer mapping. I actually hand map from the business layer to the view model because I need the flexibility.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
0

If you need performant solution, reflection may not be the right choice. In addition to the other answers, I can suggest using pre-compiled expressions because they are way more efficient and by using them you can benefit from type safety. You can read more about the idea in this article on Medium.

You can also check out the TryAtSoftware.Extensions.Reflection - it exposes extension methods that can help construct appropriate expressions. It is open-source and available as a NuGet package.

Tony Troeff
  • 338
  • 4
  • 19