/// <summary>
        /// Updates a material found by id to match newMaterial. Will validate all the data passed. Expects a full
        /// Material object to update by. Fields that are to remain the same, should still be passed holding the
        /// original value.
        /// </summary>
        /// <param name="id">The ID of the material</param>
        /// <param name="newMaterial">The new data wrapped in a Material object</param>
        /// <returns>The number of rows that were changed</returns>
        ///
        /// <exception cref="ArgumentNullException">
        /// If any of the Isbn, Title, Language or Description properties
        /// are null or empty
        /// </exception>
        ///
        /// <exception cref="ArgumentException">
        /// If MaterialType, any of MaterialSubjects or any of MaterialAuthors can't
        /// be found in the database
        /// </exception>
        ///
        /// <remarks>NOT TESTED</remarks>
        public int Update(int id, Material newMaterial)
        {
            var material = FindByID(id);

            if (material == null)
            {
                return(0);
            }

            // validate material data
            if (newMaterial.Isbn.IsNullOrEmpty())
            {
                throw new ArgumentNullException(nameof(newMaterial.Isbn), "ISBN can't be null or empty");
            }
            if (newMaterial.Title.IsNullOrEmpty())
            {
                throw new ArgumentNullException(nameof(newMaterial.Title), "Title can't be null or empty");
            }
            if (newMaterial.Language.IsNullOrEmpty())
            {
                throw new ArgumentNullException(nameof(newMaterial.Language), "Language can't be null or empty");
            }
            if (newMaterial.Description.IsNullOrEmpty())
            {
                throw new ArgumentNullException(nameof(newMaterial.Description), "Description can't be null or empty");
            }

            var materialType = _context.MaterialTypes.Find(newMaterial.Type.TypeId);

            if (materialType == null)
            {
                throw new ArgumentException("MaterialType must already exist", nameof(newMaterial.Type));
            }

            material.Isbn        = newMaterial.Isbn;
            material.Title       = newMaterial.Title;
            material.Language    = newMaterial.Language;
            material.Lendable    = newMaterial.Lendable;
            material.Description = newMaterial.Description;
            material.Type        = materialType;

            var materialSubjects = newMaterial.MaterialSubjects
                                   .Select(ms =>
            {
                var subject        = ms.MaterialSubject;
                var fetchedSubject = _context.MaterialSubjects.Find(subject.SubjectId);
                if (fetchedSubject == null)
                {
                    throw new ArgumentException("MaterialSubjects must already exist", nameof(newMaterial.MaterialSubjects));
                }

                return(new MaterialSubjects {
                    MaterialSubject = fetchedSubject, Material = material
                });
            }).ToList();

            var materialAuthors = newMaterial.MaterialAuthors
                                  .Select(ma =>
            {
                var author        = ma.Author;
                var fetchedAuthor = _authorController.FindByID(author.AuthorId);
                if (fetchedAuthor == null)
                {
                    if (author.FirstName.IsNullOrEmpty() || author.LastName.IsNullOrEmpty())
                    {
                        throw new ArgumentNullException(
                            nameof(newMaterial.MaterialAuthors),
                            "New authors must be provided with FirstName AND LastName"
                            );
                    }

                    var newAuthor = _authorController.Create(author.FirstName, author.LastName);
                    _authorController.Insert(newAuthor);

                    return(new MaterialAuthor {
                        Author = newAuthor, Material = material
                    });
                }

                return(new MaterialAuthor {
                    Author = fetchedAuthor, Material = material
                });
            }).ToList();

            // remove previous material subjects
            _context.RemoveRange(material.MaterialSubjects);
            material.MaterialSubjects = materialSubjects;

            // remove pre-existing authors
            _context.RemoveRange(material.MaterialAuthors);
            material.MaterialAuthors = materialAuthors;


            return(_context.SaveChanges());
        }