Beispiel #1
0
        public async Task <IActionResult> PartiuallyUpdateMovieAsync(
            [FromRoute, SwaggerParameter(Description = "Id of movie to update", Required = true)] Guid movieId,
            [FromBody, SwaggerParameter(Description = "Jsonpatch operation document to update", Required = true)] JsonPatchDocument <MovieToUpdateDto> patchDoc,
            [FromHeader(Name = "Accept"), SwaggerParameter(Description = "media type to request betwen json or json+hateoas")] string mediaType)
        {
            if (patchDoc == null)
            {
                return(BadRequest());
            }

            var movieFromDb = await _movieRepository.GetMovieAsync(movieId);

            //  upserting if movie does not already exist
            //  TODO:   research if upserting is neccesary in patching
            if (movieFromDb == null)
            {
                var movieToCreate = new MovieToUpdateDto();

                patchDoc.ApplyTo(movieToCreate, ModelState);

                if (!ModelState.IsValid)
                {
                    new ProccessingEntityObjectResultErrors(ModelState);
                }

                var movieToAddToDb = Mapper.Map <Movie>(movieToCreate);
                movieToAddToDb.Id = movieId;

                _movieRepository.AddMovie(movieToAddToDb);

                if (!await _movieRepository.SaveChangesAsync())
                {
                    _logger.LogError($"Upserting movie: {movieId} failed on save");
                }

                // loop on foreach Operations => if op.path == "GenreIds" => loop on value which contains list/array? of genreIds

                foreach (var op in patchDoc.Operations)
                {
                    if (op.path.ToLower() == "genreids")
                    {
                        //movieToPatch.GenreIds = (List<Guid>)op.value;
                        var genreIds = op.value.ToString();

                        // TODO make list guid instead of string so you dont have to parse on each use. What if only one, still split?
                        // TODO EXTENDED check if lenght is > 0 before all this, also check if valid Guids
                        var splitGenreIds = genreIds.Split(",");

                        switch (op.op)
                        {
                        // check if genre already exists on movie before creating
                        case "add":
                        {
                            for (int i = 0; i < splitGenreIds.Length; i++)
                            {
                                //create moviegenre object with genre id and movie id from movieToCreate object
                                MovieGenre movieGenreToAdd = new MovieGenre {
                                    MovieId = movieId, GenreId = Guid.Parse(splitGenreIds[i])
                                };
                                movieGenreToAdd.Id = Guid.NewGuid();
                                _movieGenreRepository.AddMovieGenre(movieGenreToAdd);
                            }
                            break;
                        }

                        case "replace":
                        {
                            // easy solution delete all moviegenres with id, add new ids
                            var moviegenresExist = await _movieGenreRepository.GetAllMovieGenresByMovieIdAsync(movieId);

                            // delete all existing many-to-many genre relationships for movie
                            foreach (var moviegenre in moviegenresExist)
                            {
                                _movieGenreRepository.DeleteMovieGenre(moviegenre);
                            }

                            // if any genre is added to movie, create many-to-many relationship for each genre

                            for (int i = 0; i < splitGenreIds.Length; i++)
                            {
                                // create moviegenre object with genre id and movie id from movieToCreate object
                                MovieGenre movieGenreToAdd = new MovieGenre {
                                    MovieId = movieId, GenreId = Guid.Parse(splitGenreIds[i])
                                };
                                movieGenreToAdd.Id = Guid.NewGuid();
                                _movieGenreRepository.AddMovieGenre(movieGenreToAdd);
                            }

                            break;
                        }

                        default:
                            // tell user operation not allowed?
                            break;
                        }
                    }
                }

                // save changes to database after all operations
                // check if state is modified? this will always get run
                if (!await _movieGenreRepository.SaveChangesAsync())
                {
                    _logger.LogError("Saving changes to database while dealing with a moviegenre failed");
                }

                var movieToReturn = Mapper.Map <MovieDto>(movieToAddToDb);

                if (mediaType == "application/vnd.biob.json+hateoas")
                {
                    var links = CreateLinksForMovies(movieToReturn.Id, null);

                    var linkedMovie = movieToReturn.ShapeData(null) as IDictionary <string, object>;

                    linkedMovie.Add("links", links);

                    return(CreatedAtRoute("GetMovie", new { movieId = movieToReturn.Id }, linkedMovie));
                }
                else
                {
                    return(CreatedAtRoute("GetMovie", new { movieId = movieToReturn.Id }, movieToReturn));
                }
            }

            var movieToPatch = Mapper.Map <MovieToUpdateDto>(movieFromDb);

            patchDoc.ApplyTo(movieToPatch, ModelState);

            if (!ModelState.IsValid)
            {
                new ProccessingEntityObjectResultErrors(ModelState);
            }

            Mapper.Map(movieToPatch, movieFromDb);

            _movieRepository.UpdateMovie(movieFromDb);

            if (!await _movieRepository.SaveChangesAsync())
            {
                _logger.LogError($"Partially updating movie: {movieId} failed on save");
            }

            // loop on foreach Operations => if op.path == "GenreIds" => loop on value which contains list/array? of genreIds

            foreach (var op in patchDoc.Operations)
            {
                if (op.path.ToLower() == "genreids")
                {
                    //movieToPatch.GenreIds = (List<Guid>)op.value;
                    var genreIds = op.value.ToString();

                    // TODO make list guid instead of string so you dont have to parse on each use. What if only one, still split?
                    // TODO EXTENDED check if lenght is > 0 before all this, also check if valid Guids
                    var splitGenreIds = genreIds.Split(",");

                    switch (op.op)
                    {
                    case "add":
                    {
                        for (int i = 0; i < splitGenreIds.Length; i++)
                        {
                            // checking if genre already exists on movie
                            // will fail if we use wrapper class IsDeleted checker, NOT USING ATM
                            var moviegenreToAdd = await _movieGenreRepository.GetMovieGenreByMovieIdGenreIdAsync(movieId, Guid.Parse(splitGenreIds[i]));

                            if (moviegenreToAdd == null)
                            {
                                //create moviegenre object with genre id and movie id from movieToCreate object
                                MovieGenre movieGenreToAdd = new MovieGenre {
                                    MovieId = movieId, GenreId = Guid.Parse(splitGenreIds[i])
                                };
                                movieGenreToAdd.Id = Guid.NewGuid();
                                _movieGenreRepository.AddMovieGenre(movieGenreToAdd);
                            }
                        }
                        break;
                    }

                    case "replace":
                    {
                        // easy solution delete all moviegenres with id, add new ids
                        var moviegenresExist = await _movieGenreRepository.GetAllMovieGenresByMovieIdAsync(movieId);

                        // delete all existing many-to-many genre relationships for movie
                        foreach (var moviegenre in moviegenresExist)
                        {
                            _movieGenreRepository.DeleteMovieGenre(moviegenre);
                        }

                        // if any genre is added to movie, create many-to-many relationship for each genre

                        for (int i = 0; i < splitGenreIds.Length; i++)
                        {
                            // create moviegenre object with genre id and movie id from movieToCreate object
                            MovieGenre movieGenreToAdd = new MovieGenre {
                                MovieId = movieId, GenreId = Guid.Parse(splitGenreIds[i])
                            };
                            movieGenreToAdd.Id = Guid.NewGuid();
                            _movieGenreRepository.AddMovieGenre(movieGenreToAdd);
                        }

                        break;
                    }

                    case "remove":
                    {
                        for (int i = 0; i < splitGenreIds.Length; i++)
                        {
                            var moviegenreToDelete = await _movieGenreRepository.GetMovieGenreByMovieIdGenreIdAsync(movieId, Guid.Parse(splitGenreIds[i]));

                            _movieGenreRepository.DeleteMovieGenre(moviegenreToDelete);
                        }
                        break;
                    }

                    default:
                        // tell user operation not allowed?
                        break;
                    }
                }
            }

            // save changes to database after all operations
            // check if state is modified? this will always get run
            if (!await _movieGenreRepository.SaveChangesAsync())
            {
                _logger.LogError("Saving changes to database while dealing with a moviegenre failed");
            }

            return(NoContent());
        }