Извлечение данных внешнего ключа при использовании linq

#c# #entity-framework #entity-framework-core

#c# #entity-framework #entity-framework-core

Вопрос:

Я создаю базовую систему оценки, в которой пользователи будут вводить фильм, который мы смотрели вместе, и просматривать его с оценкой из 10. Я борюсь с тем, как получить все данные для извлечения в модель представления (требуется дополнительная работа, но в настоящее время разработчики тестируют).

Контроллер:

     [HttpGet("{id}")]
    public async Task<ActionResult<EventViewModel>> GetEventWithReview(int id)
    {
        //not much here since I really am that stuck

        if (@event == null)
        {
            return NotFound();
        }

        return null;
    }
  

ViewModel:

 public class EventViewModel
{
    public  Event Event { get; set; }
    public List<Review> Reviews { get; set; }
}
  

У меня есть модели:

Событие:

     public class Event
    {
        public int Id { get; set; }
        [ForeignKey("Event")]
        public int EventTypeID { get; set; }
        public DateTime? DateTime { get; set; }
        public string EventName { get; set; }
    }
  

EventType:

 public class EventType
{
    public int Id { get; set; }
    public string Type { get; set; }
}
  

Обзор:

 public class Review
{
    public int Id { get; set; }
    [ForeignKey("ApplicationUser")]
    public int UserID { get; set; }
    public int Rating { get; set; }
    [ForeignKey("Event")]
    public int EventID { get; set; }
}
  

Комментарии:

1. попробуйте с public List<Review> Reviews {get; set;} = new LIst<Review>(); в вашей сущности события. Оттуда у вас есть доступ ко всем обзорам для этого события следующим образом dataContext.Events.Where(x => x.Id == id).Select(...).FirstOrDedfault();

2. @spzvtbg я не уверен, как это помогает моей проблеме

Ответ №1:

Во-первых, для модели представления это должно отражать данные, которые представление хочет использовать, а не содержать сущности. Объекты всегда должны отражать состояние данных, и часто это дополнительная информация, а также реляционная модель данных, которая на самом деле не нужна представлению. Как общее правило, объект никогда не должен передаваться за пределы области DbContext, откуда он был извлечен. EF поддерживает отдельные объекты, но их нужно использовать с осторожностью и, как правило, они вызывают гораздо больше проблем, чем они стоят в проекте.

Цель модели представления — сжать данные, необходимые представлению, что повышает производительность по сети, а также защищает вашу систему от раскрытия слишком многого о своей структуре данных.

 public class EventViewModel
{
    public int Id { get; set; }
    public string EventType { get; set; }
    public DateTime? DateTime { get; set; }
    public string EventName { get; set; }
    public ICollection<ReviewViewModel> Reviews { get; set; }
}

public class ReviewViewModel
{
    public string UserName { get; set; }
    public int Rating { get; set; }
}
  

Затем, когда вы переходите к выбору события и его просмотру, вы используете нечто, называемое проекцией, для преобразования объектов в модели представления. Это делается вручную с помощью Select() или может быть автоматизировано с помощью библиотеки, подобной AutoMapper, которая имеет ProjectTo<T>() метод.

В идеале в ваш контроллер должен быть введен DbContext, однако в качестве отправной точки этот пример просто охватывает DbContext в запросе:

 [HttpGet("{id}")]
public async Task<ActionResult<EventViewModel>> GetEventWithReview(int id)
{
    using(var context = new YourAppDbContext())
    {
        var event = await context.Events
            .Where(x => x.Id == id)
            .Select(x => new EventViewModel
            {
                Id = x.Id,
                EventType = x.EventType.Name,
                DateTime = x.DateTime,
                EventName = x.EventName,
                Reviews = x.Reviews
                    .Select(r => new ReviewModel
                    {
                       UserName = r.User.Name,
                       Rating = r.Rating
                    }).ToList()
            }).SingleAsync();

        return View(event);
    }
}
  

В приведенной проекции делается несколько предположений. Например, если у вас есть объект EventType для типа события, мы можем просто захотеть отобразить тип события в виде строки с событием, поэтому нет необходимости создавать модель представления типа события, только Select EventType.Введите имя как «EventType» в EventViewModel. ViewModels могут сглаживать реляционные данные, представленные объектами, таким образом, чтобы передавать только ту информацию, которую может использовать представление, а не все. То же самое было сделано, чтобы получить имя пользователя для обзора (при условии, что свойство навигации пользователя в обзоре), поэтому, если вы хотите перечислить отзывы, у вас может быть имя пользователя, комментарий и рейтинг. Если не требуется, то вы могли бы даже просто использовать a List<int> для рейтингов и использовать x.Ratings.Select(r => r.Rating).ToList() , чтобы просто получить рейтинг # ‘s. Вы можете дополнительно уточнить запрос, если хотите выполнить такие действия, как извлечение самых последних 10 оценок или тому подобное в выражении запроса с помощью OrderBy и Take . EF сведет все это к SQL, чтобы извлечь только данные, необходимые для заполнения модели представления. (Быстрее и меньше памяти, используемой на сервере) Преимущество проекции заключается в том, что вы можете запрашивать значения у связанных объектов через их навигационные свойства, как вам нужно в выражении запроса, не беспокоясь о быстрой загрузке / w Include() . EF разработает построение запроса для заполнения всего, что вы извлекаете с помощью Select .