2017-02-22 23 views
1

Я использую Entity Framework Core после блога Chris Sakell here.Entity Framework Core - проблема с объектами, связанными с загрузкой, которые также содержат связанные объекты

Он использует generics для управления своими репозиториями, а также базовый репозиторий, который он использует для всех других репозиториев.

Часть базового репозитория имеет следующий код для извлечения единого объекта, который также загружает связанные объекты, используя опцию includeProperties. Вот общий код для извлечения одного элемента.

public T GetSingle(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties) 
{ 
    IQueryable<T> query = _context.Set<T>(); 

    foreach (var includeProperty in includeProperties) 
    { 
     query = query.Include(includeProperty); 
    } 

    return query.Where(predicate).FirstOrDefault(); 
} 

Я использую его на столе клиента, к которому прилагается много заданий.

Вот как я структурировал свой код.

public ClientDetailsViewModel GetClientDetails(int id) 
    { 
     Client _client = _clientRepository 
      .GetSingle(c => c.Id == id, c => c.Creator, c => c.Jobs, c => c.State); 

     if(_client != null) 
     { 
      ClientDetailsViewModel _clientDetailsVM = mapClientDetailsToVM(_client); 
      return _clientDetailsVM; 
     } 
     else 
     { 
      return null; 
     } 
    } 

Линия:

.GetSingle(c => c.Id == id, c => c.Creator, c => c.Jobs, c => c.State); 

успешно извлекает значения для состояния творца и работы.

Однако ничего не получено для этих связанных объектов, связанных с «заданиями».

enter image description here

В particuar, JobVisits представляет собой совокупность посещений рабочих мест.

Для полноты я добавляю в «работу» и «jobvisit» сущности ниже

public class Job : IEntityBase 
{ 
    public int Id { get; set; } 

    public int? ClientId { get; set; } 
    public Client Client { get; set; } 

    public int? JobVisitId { get; set; } 
    public ICollection<JobVisit> JobVisits { get; set; } 

    public int? JobTypeId { get; set; } 
    public JobType JobType { get; set; } 

    public int? WarrantyStatusId { get; set; } 
    public WarrantyStatus WarrantyStatus { get; set; } 

    public int? StatusId { get; set; } 
    public Status Status { get; set; } 

    public int? BrandId { get; set; } 
    public Brand Brand { get; set; } 

    public int CreatorId { get; set; } 
    public User Creator { get; set; } 

    .... 
} 

public class JobVisit : IEntityBase 
{ 
    ... 
    public int? JobId { get; set; } 
    public Job Job { get; set; } 

    public int? JobVisitTypeId { get; set; } 
    public JobVisitType VisitType { get; set; } 
} 

Мой вопрос, как я могу изменить код хранилища выше, и мой GetSingle использование, так что я могу также загрузить соответствующий enitities JobVisit коллекция и другие связанные с этим отдельные компании Brand и JobType?

ответ

1

Предполагается, что свойства навигации не нужны для получения, связанных с «заданиями». Вот почему некоторые свойства: null. По умолчанию .Include(property); идет только на 1 уровень, и это хорошо. Это предотвращает получение запроса из всех данных вашей базы данных.

Если вы хотите включить несколько уровней, вы должны использовать .ThenInclude(property) после .Include(property). Из documentation:

using (var context = new BloggingContext()) 
{ 
    var blogs = context.Blogs 
     .Include(blog => blog.Posts) 
      .ThenInclude(post => post.Author) 
     .ToList(); 
} 

Мой совет, что ваш метод public T GetSingle(...) хорошо, и я бы не изменить его для того, чтобы включить более глубокие уровни. Вместо этого вы можете просто использовать явную загрузку. От documentation:

using (var context = new BloggingContext()) 
{ 
    var blog = context.Blogs 
     .Single(b => b.BlogId == 1); 

    context.Entry(blog) 
     .Collection(b => b.Posts) 
     .Load(); 

    context.Entry(blog) 
     .Reference(b => b.Owner) 
     .Load(); 
}