2011-05-27 2 views
15

Disons que j'ai une série d'objets qui forment un agrégat.Comment sélectionner efficacement un objet agrégé à l'aide de Dapper?

public class C{ 
public string Details {get;set;} 
} 

public class B{ 
    public string Details {get;set;} 
    public List<C> Items {get;set;} 
} 

public class A{ 
    public long ID {get;set;} 
    public string Details {get;set;} 
    public List<B> Items {get;set;} 
} 

utilisant Dapper, quelle est la meilleure façon de remplir ces tables à partir d'une base (dans mon cas, il est postgres mais cela ne devrait pas d'importance). Les tables de l'exemple sont à peu près identiques au modèle objet. La propriété Items de la classe représentant les relations de clé étrangère avec chaque objet subordonné. c'est-à-dire 3 tables, A a une relation un à plusieurs avec B, B a une relation un à plusieurs avec 0

Donc, pour un ID donné de A, je veux que mes objets aient aussi toutes leurs données enfants.

Ma meilleure idée est que je devrais utiliser QueryMultiple en quelque sorte, mais je ne suis pas sûr de la meilleure façon de le faire.

+0

Peut-être que la méthode 'QueryMultiple'? Je viens de télécharger dapper .. en supposant que vous faites référence à «dapper-dot-net». – IAbstract

+0

yep dapper-dot-net est ce que j'expérimente. – Peter

+0

Ce que je fais actuellement est un QueryMultiple sur toutes les différentes tables, puis en utilisant linq pour assigner par id aux collections enfants. cela signifie que je fais un batch à la base de données et que je fais tout le travail en RAM plutôt que ce que j'ai vu linq2sql qui est un hangar chargé de requêtes incidentes à la db ... Je suis plutôt content du résultat que je viens de faire Je me demandais si mon approche était/est l'intention de l'auteur dapper. – Peter

Répondre

11

Je pense que l'assistant que je propose ici: Multi-Mapper to create object hierarchy peut être utile.

var mapped = cnn.QueryMultiple(sql) 
    .Map<A,B,A> 
    (
     A => A.ID, 
     B => B.AID, 
     a, bees => { A.Items = bees}; 
    ); 

En supposant que vous étendez votre GridReader et avec un mappeur:

public static IEnumerable<TFirst> Map<TFirst, TSecond, TKey> 
    (
    this GridReader reader, 
    Func<TFirst, TKey> firstKey, 
    Func<TSecond, TKey> secondKey, 
    Action<TFirst, IEnumerable<TSecond>> addChildren 
    ) 
{ 
    var first = reader.Read<TFirst>().ToList(); 
    var childMap = reader 
     .Read<TSecond>() 
     .GroupBy(s => secondKey(s)) 
     .ToDictionary(g => g.Key, g => g.AsEnumerable()); 

    foreach (var item in first) 
    { 
     IEnumerable<TSecond> children; 
     if(childMap.TryGetValue(firstKey(item), out children)) 
     { 
      addChildren(item,children); 
     } 
    } 

    return first; 
} 

Vous pouvez étendre ce modèle à travailler avec une hiérarchie à 3 niveaux.

+0

Ceci est une bonne solution, merci – Peter

+1

Cela ne fonctionne pas pour moi. Lorsqu'il essaie de lire TSecond, le lecteur a été consommé et ne peut pas être lu à nouveau. –

+0

@Mr Grok - moi aussi. Avez-vous trouvé une solution à cela? – BZink