Skip to content

Instantly share code, notes, and snippets.

@eterekhin
Last active February 25, 2020 09:09
Show Gist options
  • Save eterekhin/57f90b673a2b7633e7073f4aa5c2ba4c to your computer and use it in GitHub Desktop.
Save eterekhin/57f90b673a2b7633e7073f4aa5c2ba4c to your computer and use it in GitHub Desktop.

При проекции в DTO, если проекция происходит в IEnumerable, то entity framework не будет вытягивать эти данные при запросе, а вытянет после при обращении к этой коллекции, поэтому и возникает n+1 запрос. Чтобы избежать этого, можно поменять тип свойства на массив, тогда при проекции automapper сам сделате ToArray:

public class Dto{
  public SomeCollection[] arr;
}
public class Entity{
  SomeEntity[] SomeCollection{get;set;}
}

public class AutoMapperProfile:Profile{
  AutoMapperProfile(){
  
    CreateMap<Entity,Dto>().ForMember(x=>x.arr,x=>x.SomeCollection); 
  }
  
  // using
  var q = query.ProjectTo<Dto>();
  // автомаппер сам сделает :
  // expression из q - dbSet.Select(x=>new Dto(){arr = x.SomeCollection.ToArray()}
  //
}

Если сделать коллекцию массивом, то будет сделан всего один дополнительный запрос(join между Entity и SomeEntity и orderby по Entityid результатов, после этого сопоставляется (в c# коде) по EntityId сджойненные записи и результирующая последовательность). Таким образом делается все 2 запроса, первый результирующий, второй тянущий сджойненные SomeEntity и Entity.

А что будет если arr будет иметь тип IEnumerable, тогда (без указания явного ToList или ToArray в маппинге), автомаппер не будет достраивать вызов этих методов, и вернется EnumerableAdapter(entity framework core 2.2). Которая при вызове GetEnumerator, будет делать запрос

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment