8
 public CodeCustomMapper()
  {

    Map(f => f.Name).Column("SName");
    Map(f => f.Name).Column("TName");
    Map(f => f.EmailID).Column("wmail");
    Map(f => f.EmailID).Column("Email");
   }

I want create this kind of map for dapper.query function.
Please can anybody help?
I want to map custom column names to entity property names.


public class EntityBase
{
    public string CreatedBy { get; set; }
    public DateTime CreatedOn { get; set; }
}

public class Person :EntityBase
{
    public string SecurityAlias{ get; set; }
    public DateTime Identifier{ get; set; }
}

public class EntityBaseMap
{
    public EntityBaseMap()
    {
        var map = new CustomTypeMap<EntityBase>();
        map.Map("CreatingPerson", "CreatedBy");
        map.Map("CreatedDate", "CreatedOn");
        SqlMapper.SetTypeMap(map.Type, map);
    }
}

public class PersonMap
{
    public PersonMap()
    {
        var map = new CustomTypeMap<Person>();
        map.Map("security_alias", "SecurityAlias");
        map.Map("Id", "Identifier");
        SqlMapper.SetTypeMap(map.Type, map);
    }
}

When I call this:

EntityBaseMap entityBaseMap = new EntityBaseMap();
PersonMap personMap = new PersonMap();

now if I use Person entity it's not mapping EntityBase properties inside the person entity.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Gaurav Moolani
  • 342
  • 1
  • 3
  • 12

1 Answers1

13

Basically, you need to write an ITypeMap and IMemberMap implementation, which internally could be based on any rules you choose (naming conventions such as removing S etc identifiers, underscores, etc; attributes; or custom maps as in your case).

Here's a complete runnable example that may help:

using Dapper;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;

class SomeType
{
    public string Bar { get; set; }
    public int Foo { get; set; }
}

static class Program
{
    static Program()
    {
        // only need to do this ONCE
        var oldMap = SqlMapper.GetTypeMap(typeof(SomeType));
        var map = new CustomTypeMap(typeof(SomeType), oldMap);
        map.Map("IFoo", "Foo");
        map.Map("SBar", "Bar");
        SqlMapper.SetTypeMap(map.Type, map);
    }

    static void Main()
    {
        using (var conn = new SqlConnection("Server=.;Database=master;Trusted_Connection=true"))
        {
            conn.Open();

            var row = conn.Query<SomeType>("select 123 as [IFoo], 'abc' as [SBar]").Single();
            Console.WriteLine(row.Foo);
            Console.WriteLine(row.Bar);
        }
    }

    class CustomTypeMap : SqlMapper.ITypeMap
    {
        private readonly Dictionary<string, SqlMapper.IMemberMap> members
            = new Dictionary<string, SqlMapper.IMemberMap>(StringComparer.OrdinalIgnoreCase);
        public Type Type { get { return type; } }
        private readonly Type type;
        private readonly SqlMapper.ITypeMap tail;
        public void Map(string columnName, string memberName)
        {
            members[columnName] = new MemberMap(type.GetMember(memberName).Single(), columnName);
        }
        public CustomTypeMap(Type type, SqlMapper.ITypeMap tail)
        {
            this.type = type;
            this.tail = tail;
        }
        public System.Reflection.ConstructorInfo FindConstructor(string[] names, Type[] types)
        {
            return tail.FindConstructor(names, types);
        }

        public SqlMapper.IMemberMap GetConstructorParameter(
            System.Reflection.ConstructorInfo constructor, string columnName)
        {
            return tail.GetConstructorParameter(constructor, columnName);
        }

        public SqlMapper.IMemberMap GetMember(string columnName)
        {
            SqlMapper.IMemberMap map;
            if (!members.TryGetValue(columnName, out map))
            { // you might want to return null if you prefer not to fallback to the
              // default implementation
                map = tail.GetMember(columnName);
            }
            return map;
        }
    }
    class MemberMap : SqlMapper.IMemberMap
    {
        private readonly MemberInfo member;
        private readonly string columnName;
        public MemberMap(MemberInfo member, string columnName)
        {
            this.member = member;
            this.columnName = columnName;
        }
        public string ColumnName { get { return columnName; } }
        public System.Reflection.FieldInfo Field { get { return member as FieldInfo; } }
        public Type MemberType { get {
            switch (member.MemberType)
            {
                case MemberTypes.Field: return ((FieldInfo)member).FieldType;
                case MemberTypes.Property: return ((PropertyInfo)member).PropertyType;
                default: throw new NotSupportedException();
            }
        } }
        public System.Reflection.ParameterInfo Parameter { get { return null; } }
        public System.Reflection.PropertyInfo Property { get { return member as PropertyInfo; } }
    }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanku Marc for the quick reply . One more question if i am using a MVC application in which i have Data layer(where i will be using dapper) . My question is where i can write the code provide by u so that i have to do this mapping on startup only once.? – Gaurav Moolani Dec 22 '12 at 03:47
  • 1
    @CodeCrusher easiest place would be to call down to an Init method in the DAL from global.asax, near where you configure MVC routes – Marc Gravell Dec 22 '12 at 07:48
  • Hi Marc the code is not working if i am having a base entity. its not mapping the properties of base entity. even though i am mapping base entity saperately. – Gaurav Moolani Jan 02 '13 at 13:33
  • @CodeCrusher can you provide an example? – Marc Gravell Jan 02 '13 at 14:44
  • public class Client : EntityBase . Entitybase i am mapping as given by u . also Client separetly. – Gaurav Moolani Jan 02 '13 at 14:59
  • Hi Marc i edited my post and added example please see example above in post – Gaurav Moolani Jan 02 '13 at 16:21
  • i think dapper should also check for its base classes automatically – Gaurav Moolani Jan 03 '13 at 09:13
  • @CodeCrusher isn't that all specific to `CustomTypeMap`, though? can't you just change `CustomTypeMap`? – Marc Gravell Jan 03 '13 at 09:18
  • I can change CustomTypeMap but if the condition like this is present. "Child class :- having no maps and Base class having maps" then i have to map forcefully child class even thought its not having any maps. – Gaurav Moolani Jan 03 '13 at 09:26
  • thanks for ur effort i am in a difficult situation like this . If i am having 100 entities all of them inherited from base class ("which needs custom mapping") . and only 10 of them need mapping then i have to apply "CustomTypeMap" to all 100 entities. – Gaurav Moolani Jan 03 '13 at 09:33
  • any solution? for the problem – Gaurav Moolani Jan 04 '13 at 09:49
  • Is there no easier solution to this common problem of needing to map a SQL column name to a POCO field? I'd prefer not to resort to Attributes. Why isn't something like this included in Dapper by default? – crush Oct 13 '14 at 15:29
  • @crush because the entire point of dapper is to solve the 98% problem without introducing vast swathes of complexity simply to support the 2% – Marc Gravell Oct 13 '14 at 15:31
  • @MarcGravell The ability to easily map a column name to a field without resorting to decorating fields with an attribute (which effectively couples the database schema to a POCO), seems like something that would fall closer to solving the 98% than the 2%. The above solves a very-broad scoped, non-implementation specific issue. I understand the point you are making, but I feel like the "CustomTypeMapper" is an essential piece of the Dapper toolkit. I've ended up adding this to every project I write that uses Dapper, since I refuse to couple POCOs to the database implementation. Just my 2 cents. – crush Oct 13 '14 at 18:19
  • A, possibly, better answer can be found at http://stackoverflow.com/a/12615036/521554 where one adds attributes to the POCO class like how it is done in EF. – LosManos Apr 10 '15 at 21:46