2
\$\begingroup\$

In the current project that I am working on, we are using dapper to query the database and sometime when mapping from dynamic types to concrete types we end up with a messy block of code.

I created a folder called mappers and have created an Interface<T>, an abstract class inheriting from that interface and I have also set up my IOC to map according to naming conventions so that I can inject my mappers through the constructor of my query classes.

public interface IMapper<out T>
    {
        T Map(SqlMapper.GridReader reader);
    }

    public abstract class MapperBase<T> : IMapper<T>
    {
        public abstract T Map(SqlMapper.GridReader reader);
    }

    public class UserDto
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class UserDtoMapper : MapperBase<UserDto>
    {
        public override UserDto Map(SqlMapper.GridReader reader)
        {
            return reader.Read().Select(x => new UserDto()
            {
                Id = x.Id,
                Name = x.Name
            }).SingleOrDefault();
        }
    }

    public class QueryObject
    {
        private IMapper<UserDto> userDtoMapper; 

        public QueryObject(IMapper<UserDto> userDtoMapper)
        {
            this.userDtoMapper = userDtoMapper;
        }

        public UserDto Query(int id)
        {
            ..........
             return userDtoMapper.Map(reader)
            ...
        }
    }
\$\endgroup\$
3
  • \$\begingroup\$ Is there a reason you haven't gone with AutoMapper instead? \$\endgroup\$ Feb 25, 2015 at 18:59
  • \$\begingroup\$ from what I have read, automapper does not support dynamic mapping if the names of properties are different and need to be configured manually, which in our project most often is the case. \$\endgroup\$
    – xerxes
    Feb 25, 2015 at 19:05
  • 1
    \$\begingroup\$ Indeed, you will have to configure the mapping explicitly. But as far as I can tell you're doing that too now and you have to do it for each property, even when the names are the same. \$\endgroup\$ Feb 25, 2015 at 19:28

1 Answer 1

1
\$\begingroup\$

Setting aside that you won't go with a Mapping framework like Jeroen Vannevel suggested in his comment, this basically looks good but can still be improved.

I don't see any value added by creating an abstract class which implements the IMapper<T> interface. So you better just do it like

public class UserDtoMapper : IMapper<UserDto>
{
    public UserDto Map(SqlMapper.GridReader reader)
    {
        return reader.Read().Select(x => new UserDto()
        {
            Id = x.Id,
            Name = x.Name
        }).SingleOrDefault();
    }
}

But if you travel this route you should do it right and also make QueryObject class generic like

public class QueryObject<T>
{
    private IMapper<T> mapper; 

    public QueryObject(IMapper<T> mapper)
    {
        this.mapper = mapper;
    }

    public T Query(int id)
    {
        ..........
         return mapper.Map(reader)
        ...
    }
}  
\$\endgroup\$
3
  • \$\begingroup\$ I chose the abstract class route cause I thought we might be able to add some shared methods to the abstract class in the future which could be used by all the inheriting classes. \$\endgroup\$
    – xerxes
    Feb 26, 2015 at 8:33
  • \$\begingroup\$ if i make the query object generic too, would I have to make the implementations work on a single dto or can the implementations include query methods for different types of Dtos? \$\endgroup\$
    – xerxes
    Feb 26, 2015 at 8:40
  • \$\begingroup\$ In its current form it would only work on a single dto. Maybe it can be extended to serve for different dto's also, but there isn't enough code in the question to answer this. If you want to change the code in question, drop me a short comment here so I can delete (temprorary) this answer so you won't violate the site rules. \$\endgroup\$
    – Heslacher
    Feb 26, 2015 at 8:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.