Multi mapping query with Dapper

.net c# dapper sql sql-server

Question

I have these classes and their equivalent tables in my database:

public class Entity
{
    public int Id { get; set; }
    public List<EntityIdentifier> Identifiers { get; set; }

    public BaseEntity()
    {
        Identifiers = new List<EntityIdentifier>();
    }
}

public class EntityIdentifier
{
    public int Id { get; set; }
    public int EntityId { get; set; }

    public string Code { get; set; }
    public string Value { get; set; }
}

I want to query the database with Dapper and automap the data.

I have this example of multi mapping, from the Dapper git page:

var sql = 
@"select * from #Posts p 
left join #Users u on u.Id = p.OwnerId 
Order by p.Id";

var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post;});
var post = data.First();

post.Content.IsEqualTo("Sams Post1");
post.Id.IsEqualTo(1);
post.Owner.Name.IsEqualTo("Sam");
post.Owner.Id.IsEqualTo(99);

However, in this example, each child (post) has a link to its parent (user). In my case, it is the parent (entity) that points to a list of children (identifiers).

How do I need to adapt the code to my case?


Here is the SQL query that I am using:

SELECT e.*, i.*
FROM Entity e INNER JOIN EntityIdentifier i ON i.EntityId = e.Id

Accepted Answer

This is an example I have found somewhere on the Dapper related sites. The point here is to have a dictionary where you keep the Entity.ID as key and Entity as dictionary value. Then in the lambda expression you check if the dictionary already contains the Entity, if yes just add the EntityIdentifier to the Entity list otherwise add the Entity returned by Dapper to the Dictionary

string cmdText = @"SELECT e.*, i.*
                   FROM Entity e INNER JOIN Identifier i ON i.EntityId = e.Id";
var lookup = new Dictionary<int, Entity>();
using (IDbConnection connection = OpenConnection())
{
    var multi = connection.Query<Entity, EntityIdentifier, Entity>(cmdText, 
                                (entity, identifier) =>
    {
        Entity current;
        if (!lookup.TryGetValue(entity.ID, out current))
        {
            lookup.Add(entity.ID, current = entity);
            current.Identifiers = new List<EntityIdentifier>();
        }
        current.Identifiers.Add(identifier);
        return current;
    }, splitOn: "i.ID").Distinct();
    return multi;
}

Sometime this becomes complicated by the parameter splitOn. Not sure if you need to repeat it adding explicitly to the Select statement (I usually use the IDTable pattern)



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why