MVC Изменение данных EF через свойство навигации - PullRequest
0 голосов
/ 22 марта 2019

Я недавно закончил курс MVC по udemy, который создал приложение для проката видео.Он рассказал о том, как посмотреть фильм, но оставил нас в покое, чтобы выяснить, как вернуть его обратно.

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

public class Customer
    {
        public int Id { get; set; }

        [Required(ErrorMessage = "Please enter customer's name.")]
        [StringLength(255)]
        public string Name { get; set; }

        public bool IsSubscribedToNewsletter { get; set; }

        [Display(Name = "Date of Birth")]
        [Min18YearsIfAMember]  
        public DateTime? Birthdate { get; set; }

        public MembershipType MembershipType { get; set; }  

        [Display(Name = "Membership Type")]
        public byte MembershipTypeId { get; set; } 
    }

Модель фильма:

public class Movie
    {
        public int Id { get; set; }

        [Required]
        [StringLength(255)]
        public string Name { get; set; }

        public Genre Genre { get; set; }

        [Display(Name = "Genre")]
        [Required]
        public byte GenreId { get; set; }

        [Display(Name = "Release Date")]
        public DateTime ReleaseDate { get; set; }

        public DateTime DateAdded { get; set; }

        [Display(Name = "Number in Stock")]
        [Range(1, 20)]
        public byte NumberInStock { get; set; }

        public byte NumberAvailable { get; set; }
    }

И модель проката, которая содержит клиента и фильм:

public class Rental
    {
        public int Id { get; set; }

        [Required]
        public Customer Customer { get; set; }

        [Display(Name = "Customer Name")]
        public int CustomerId { get; set; }

        [Required]
        public Movie Movie { get; set; }

        public DateTime DateRented { get; set; }

        public DateTime? DateReturned { get; set; }
    }

Я сделал представление, которое будет отображать активные прокаты, и сделал действие Удалить, которое удалит его, как если быФильм был добавлен, но я не могу понять, как вернуть этот фильм в запас, увеличив количество доступных фильмов (Movies.NumberAvailable).Я пытался сделать это в том же действии, что и действие Удалить, но мне не повезло.Вот действие «Удалить»:

public ActionResult Delete(int id)  
        {
            Rental rental = _context.Rentals.Find(id);
            //var movie = _context.Movies.Where(m => rental.Movie.Id.Contains(m.Id));
            rental.Movie.NumberAvailable++;

            _context.Rentals.Remove(rental);
            _context.SaveChanges();

            return RedirectToAction("List");
        }

Я пытался извлечь только этот фильм в его собственную переменную и добавить к нему 1, но часть rental.Movie.Id выдавала ошибку, говоря, что у нее нет определения для контейнера.,Если я запускаю его, как указано выше, я получаю исключение на rental.Movie.NumberAvailable++;, говорящее «Ссылка на объект не установлена ​​для экземпляра объекта».?Да, я нуб.

Ответы [ 2 ]

0 голосов
/ 22 марта 2019

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

  1. Отслеживание экземпляров фильма и их статуса и вычисление итогов по запросу.

Это будет что-то вроде класса Movie, но тогда у каждого фильма будет коллекция MovieDisc, например:

public class MovieDisc
{
   public int MovieDiscId{ get; set; }
   public bool InStock { get; set; }
   public string Barcode { get; set; }
}

В основном, когда фильмы извлекаются или сканируются, их штрих-код идентифицирует «диск» или экземпляр и устанавливает InStock. Со стороны фильма:

public class Movie 
{
   // ...

   public virtual ICollection<MovieDisc> Discs {get; internal set;} = new List<MovieDisc>();
   public byte NumberInStock 
   { 
      get { return Discs.Count(x => x.InStock); }
   }

   public byte NumberAvailable 
   { 
      get { return Discs.Count(x => !x.InStock); }
   }
}

Предостережение этого подхода заключается в том, что для использования этих свойств коллекция Discs должна быть загружена с нетерпением или отключит отложенную загрузку.

  1. Принять подход DDD к сущностям.

Domain Driven Design по существу добавляет элементы управления изменением состояния в домене. Вместо того, чтобы использовать отдельные установщики для значений, вы используете методы или действия с сущностью домена для проверки и контроля допустимых и полных изменений, разрешенных для домена.

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(255)]
    public string Name { get; private set; }

    public Genre Genre { get; private set; }

    [Display(Name = "Genre")]
    [Required]
    public byte GenreId { get; private set; }

    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; private set; }

    public DateTime DateAdded { get; private set; }

    [Display(Name = "Number in Stock")]
    [Range(1, 20)]
    public byte NumberInStock { get; private set; }

    public byte NumberAvailable { get; private set; }

    public void RentOneOut()
    {
       if (NumberInStock <= 0)
          throw new InvalidOperation("Cannot rent out a movie that has no stock.");
       if (NumberAvailable <= 0)
          throw new InvalidOperation("All movie copies are out.");

       NumberAvailable -= 1;
    }

    public void ReturnOneIn()
    {
       if (NumberInStock <= 0)
          throw new InvalidOperation("Cannot return a movie that has no stock.");
       if (NumberAvailable >= NumberInStock)
          throw new InvalidOperation("All movie copies are already in. Stocktake needed.");

       NumberAvailable += 1;
    }
}

Обратите внимание, что все сеттеры являются частными. (или внутренний, если вы хотите включить модульное тестирование). Цель состоит в том, чтобы выразить допустимые операции в отношении объекта домена в качестве метода. Это гарантирует, что несколько проверок и обновлений выполняются как единое целое, так что несколько свойств могут быть обновлены вместе, не рискуя оставить объект в неполном состоянии.

Это может быть более практичным для вашего сценария аренды:

public function ReturnRental(Rental rental)
{
   if (rental == null)
      throw new ArgumentNullException("rental");

   rental.Return();
}

// In Rental:
public class Rental
{
   // ...  private setters, like in Movie.

   public void Return()
   {
      Movie.ReturnOneIn();
      DateReturned = DateTime.Today;
   }
}

Вы бы хотели обработать сценарий, в котором возврат по какой-либо причине не удался. (состояние данных не синхронизировано)

Надеюсь, это даст вам несколько идей.

0 голосов
/ 22 марта 2019

попробуй:

Rental rental = _context.Rentals.Where(r => r.Id == id).FirstOrDefault();
rental.Movie.NumberAvailable++;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...