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?
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
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;
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();
}
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();
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.
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;