Как сопоставить списки вложенных объектов с помощью Dapper
в настоящее время я использую Entity Framework для моего доступа к БД, но хочу взглянуть на Dapper. У меня есть такие классы:
public class Course{
public string Title{get;set;}
public IList<Location> Locations {get;set;}
...
}
public class Location{
public string Name {get;set;}
...
}
Итак, один курс может преподаваться в нескольких местах. Entity Framework выполняет сопоставление для меня, поэтому мой объект курса заполняется списком местоположений. Как бы я пошел на это с Dapper, возможно ли это вообще или мне нужно сделать это в несколько шагов запроса?
6 ответов:
Dapper не является полномасштабным ORM, он не обрабатывает магическую генерацию запросов и т. д.
для вашего конкретного примера, вероятно, будет работать следующее:
возьмите курсы:
var courses = cnn.Query<Course>("select * from Courses where Category = 1 Order by CreationDate");возьмите соответствующее отображение:
var mappings = cnn.Query<CourseLocation>( "select * from CourseLocations where CourseId in @Ids", new {Ids = courses.Select(c => c.Id).Distinct()});захватите соответствующие места
var locations = cnn.Query<Location>( "select * from Locations where Id in @Ids", new {Ids = mappings.Select(m => m.LocationId).Distinct()} );карта все
оставляя это читателю, вы создаете несколько карт и повторяете свои курсы, заполняя их места.
будьте осторожны the
inтрюк будет работать, если у вас меньше lookups (Sql Server), если у вас есть больше, вы, вероятно, хотите изменить запрос наselect * from CourseLocations where CourseId in (select Id from Courses ... )если это так, вы можете также дергать все результаты за один раз, используяQueryMultiple
кроме того, вы можете использовать один запрос с поиска:
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;смотрите здесь https://www.tritac.com/blog/dappernet-by-example/
Я знаю, что я действительно опаздываю к этому, но есть и другой вариант. Вы можете использовать QueryMultiple здесь. Что-то вроде этого:
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(); }
не нужно
lookupсловарь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();
чего-то не хватает. Если не указать каждое поле из расположений в SQL-запросе, расположение объекта не может быть заполнено. Взгляните:
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;используя "l.*" в запросе, у меня был список местоположений, но без данных.
Не уверен, что это кому-то нужно, но у меня есть динамическая версия без модели для быстрого и гибкого кодирования.
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;
Comments