J'ai ces classes et leurs tables équivalentes dans ma base de données:
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; }
}
Je souhaite interroger la base de données avec Dapper et automatiser les données.
J'ai cet exemple de multi-mapping, à partir de la page gapp de Dapper :
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);
Cependant, dans cet exemple, chaque enfant (post) a un lien vers son parent (utilisateur). Dans mon cas, c'est le parent (entité) qui pointe vers une liste d'enfants (identifiants).
Comment dois-je adapter le code à mon cas?
Voici la requête SQL que j'utilise:
SELECT e.*, i.*
FROM Entity e INNER JOIN EntityIdentifier i ON i.EntityId = e.Id
C'est un exemple que j'ai trouvé quelque part sur les sites liés à Dapper. Le point ici est d'avoir un dictionnaire où vous gardez Entity.ID comme clé et Entity comme valeur de dictionnaire. Ensuite, dans l'expression lambda, vous vérifiez si le dictionnaire contient déjà l'entité, si oui, ajoutez simplement l'entité EntityIdentifier à la liste des entités, sinon ajoutez l'entité renvoyée par Dapper au dictionnaire.
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;
}
Parfois, cela devient compliqué par le paramètre splitOn. Vous ne savez pas si vous devez le répéter en ajoutant explicitement à l'instruction Select (j'utilise généralement le modèle IDTable)