Comment puis-je map des listes d'objets imbriqués avec Dapper

j'utilise actuellement Entity Framework pour mon accès db mais je veux jeter un oeil à Dapper. J'ai des cours comme celui-ci:

public class Course{
   public string Title{get;set;}
   public IList<Location> Locations {get;set;}
   ...
}

public class Location{
   public string Name {get;set;}
   ...
}

ainsi un cours peut être enseigné à plusieurs endroits. Entity Framework fait la cartographie pour moi ainsi mon objet de cours est peuplé avec une liste d'emplacements. Comment vais-je faire avec Dapper, est-ce possible ou dois-je le faire en plusieurs étapes de requête?

85
demandé sur Kiquenet 2011-09-22 04:48:35

6 réponses

Dapper n'est pas un ORM soufflé il ne gère pas la génération magique de requêtes et autres.

pour votre exemple particulier, le suivant fonctionnerait probablement:

Saisir le cours:

var courses = cnn.Query<Course>("select * from Courses where Category = 1 Order by CreationDate");

Saisir l'cartographiques pertinentes:

var mappings = cnn.Query<CourseLocation>(
   "select * from CourseLocations where CourseId in @Ids", 
    new {Ids = courses.Select(c => c.Id).Distinct()});

Saisir les lieux les plus pertinents

var locations = cnn.Query<Location>(
   "select * from Locations where Id in @Ids",
   new {Ids = mappings.Select(m => m.LocationId).Distinct()}
);

Carte tous

laissant ceci au lecteur, vous créez quelques cartes et itérez à travers vos cours peuplant avec les emplacements.

mise en garde le in astuce ne fonctionnera que si vous avez moins de 2100 recherches (Sql Server), si vous avez plus, vous voudrez probablement modifier la requête pour select * from CourseLocations where CourseId in (select Id from Courses ... ) si c'est le cas vous pouvez ainsi tirer tous les résultats en une seule fois à l'aide de QueryMultiple

38
répondu Sam Saffron 2017-05-23 12:03:05

Alternativement, vous pouvez utiliser une requête avec une recherche:

var lookup = new Dictionary<int, Course>();
conn.Query<Course, Location, Course>(@"
                SELECT c.*, l.*
                FROM Course c
                INNER JOIN Location l ON c.LocationId = l.Id                    
                ", (c, l) => {
                     Course course;
                     if (!lookup.TryGetValue(c.Id, out course)) {
                         lookup.Add(c.Id, course = c);
                     }
                     if (course.Locations == null) 
                         course.Locations = new List<Location>();
                     course.Locations.Add(l); /* Add locations to course */
                     return course;
                 }).AsQueryable();
var resultList = lookup.Values;

voir ici https://www.tritac.com/blog/dappernet-by-example /

129
répondu Jeroen K 2017-05-02 08:45:11

je sais que je suis vraiment en retard, mais il y a une autre option. Vous pouvez utiliser QueryMultiple ici. Quelque chose comme ceci:

var results = cnn.QueryMultiple("select * from Courses where Category = 1 Order by CreationDate; select A.*, B.CourseId from Locations A Inner Join CourseLocations B on A.LocationId = B.LocationId Inner Join Course C On B.CourseId = B.CourseId And C.Category = 1");

var courses = results.Read<Course>();
var locations = results.Read<Location>(); //(Location will have that extra CourseId on it for the next part)
foreach (var course in courses) {
   course.Locations = locations.Where(a => a.CourseId == course.CourseId).ToList();
}
23
répondu Daniel Lorenz 2017-02-23 16:01:44

Pas besoin de lookup Dictionnaire

var coursesWithLocations = 
       conn.Query<Course, Location, Course>(@"
            SELECT c.*, l.*
            FROM Course c
            INNER JOIN Location l ON c.LocationId = l.Id                    
            ", (course, location) => {
                 course.Locations = course.Locations ?? new List<Location>();
                 course.Locations.Add(location); 
                 return course;
             }).AsQueryable();
19
répondu tchelidze 2018-03-26 12:13:42

il manque quelque chose. Si vous ne spécifiez pas chaque champ À partir des emplacements de la requête SQL, L'emplacement de l'objet ne peut pas être rempli. Regardez:

var lookup = new Dictionary<int, Course>()
conn.Query<Course, Location, Course>(@"
                SELECT c.*, l.Name, l.otherField, l.secondField
                FROM Course c
                INNER JOIN Location l ON c.LocationId = l.Id                    
                ", (c, l) => {
                     Course course;
                     if (!lookup.TryGetValue(c.Id, out course)) {
                         lookup.Add(c.Id, course = c);
                     }
                     if (course.Locations == null) 
                         course.Locations = new List<Location>();
                     course.Locations.Add(a);
                     return course;
                 },
                 ).AsQueryable();
var resultList = lookup.Values;

utilisant " L.*" sur la requête, j'ai eu la liste des emplacements mais sans données.

2
répondu Eduardo Pires 2014-02-14 14:34:38

pas sûr si quelqu'un en a besoin, mais j'en ai une version dynamique sans modèle pour un codage rapide et flexible.

        var lookup = new Dictionary<int, dynamic>();
        conn.Query<dynamic, dynamic, dynamic>(@"
                        SELECT A.*, B.*
                        FROM Client A
                        INNER JOIN Instance B ON A.ClientID = B.ClientID                
                        ", (A, B) => {
                            // If dict has no key, allocate new obj
                            // with another level of array
                            if (!lookup.ContainsKey(A.ClientID)){
                                lookup[A.ClientID] = new {
                                    ClientID = A.ClientID,
                                    ClientName = A.Name,                                        
                                    Instances = new List<dynamic>()
                                };
                            }

                           // Add each instance                                
                           lookup[A.ClientID].Instances.Add(new {
                                    InstanceName = B.Name,
                                    BaseURL = B.BaseURL,
                                    WebAppPath = B.WebAppPath
                           });


                            return lookup[A.ClientID];
                        }, splitOn: "ClientID,InstanceID").AsQueryable();
        var resultList = lookup.Values;
        return resultList;
0
répondu Kiichi 2017-07-18 01:49:54