Как сопоставить списки вложенных объектов с помощью 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, возможно ли это вообще или мне нужно сделать это в несколько шагов запроса?

730   6  

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

    Ничего не найдено.