2

NOT A DUPLICATE: My Update() methods takes two arguements: id and modified entity, and answers provided to my question have different approach like CurrentValues which isn't covered in existing questions.

I am new to ASP.Net core development. I am building a simple API with MySql as database and with a Book model.

I have written my controller like following:

[Route("api/[controller]")]
    public class BooksController : Controller
    {
        private readonly IBookRepository _books;
        public BooksController(IBookRepository books)
        {
            _books = books;
        }

        [HttpGet("")]
        public IActionResult GetAllBooks()
        {
            try
            {
                List<Book> books = _books.GetAllBooks();
                return Ok(books);
            }
            catch(EntityNotFoundException<Book>)
            {
                return NotFound();
            }

        }

        [HttpGet("{id}")]
        public IActionResult GetBook(long id)
        {
            Book book = _books.GetBook(id);
            if (book == null)
            {
                return NotFound();
            }
            return Ok(book);
        }

        [HttpPost]
        public IActionResult CreateBook([FromBody] Book book)
        {
            if (ModelState.IsValid == false)
            {
                return BadRequest(ModelState);
            }

            Book createdBook = _books.CreateBook(book);
            if (createdBook == null)
            {
                return NotFound();
            }
            return CreatedAtAction(
                 nameof(GetBook), new { id = createdBook.Id }, createdBook);

        }

        [HttpPut("{id}")]
        public IActionResult UpdateBook(long id, [FromBody] Book book)
        {
            if (ModelState.IsValid == false)
            {
                return BadRequest(ModelState);
            }

            try
            {
                _books.UpdateBook(id, book);
                return Ok();
            }
            catch (EntityNotFoundException<Book>)
            {
                return NotFound();
            }
        }

        [HttpDelete("{id}")]
        public IActionResult DeleteBook(long id)
        {
            _books.DeleteBook(id);
            return Ok();
        }
    } 

And Repository as following:

public class BookRepository: IBookRepository
    {
        private readonly WebAPIDataContext _db;

        public BookRepository(WebAPIDataContext db) {
            _db = db;
        }

        public Book CreateBook(Book book) {
            _db.Books.Add(book);
            _db.SaveChanges();
            return book;
        }

        public void DeleteBook(long id)
        {
            Book book = GetBook(id);
            if (book != null) {
                _db.Books.Remove(book);
                _db.SaveChanges();
            }
        }

        public List<Book> GetAllBooks()
        {
            return _db.Books.AsNoTracking().ToList();
        }

        public Book GetBook(long id)
        {
            return _db.Books.FirstOrDefault(o => o.Id == id);
        }

        public void UpdateBook(long id, Book book)
        {


        }
    }

    public interface IBookRepository
    {
        List<Book> GetAllBooks();
        Book GetBook(long id);
        Book CreateBook(Book book);
        void UpdateBook(long id, Book book);
        void DeleteBook(long id);
    }

I am not sure how can I write the UpdateBook method in my Repo class. Can someone please help me with that? All the tutorial I saw were using single id parameter to UpdateBook() method, I am basically posting a json object as well along with entity id.

Thinker
  • 5,326
  • 13
  • 61
  • 137
  • Possible duplicate of [How to update record using Entity Framework 6?](http://stackoverflow.com/questions/25894587/how-to-update-record-using-entity-framework-6) – Yawar Murtaza Mar 17 '17 at 08:54
  • It isn't exact duplicate because my Update method takes two arguments wiz id and modified Entity and I did not find any tutorial or blogpost that does update like this. I think it is more convenient to update the entire entity rather than updating all it's properties one by one – Thinker Mar 17 '17 at 08:57
  • It says "Possible duplicate" secondly, if you look into that post it clearly shows to get the entity from the database using id, then set its properties from the one you want to update, then save back into the database. It doesnt matter if you are posting a json object, at the dataAccess level / repository layer its just a POCO object. – Yawar Murtaza Mar 17 '17 at 09:18

3 Answers3

8

Try this

  public void UpdateBook(long id, Book book)
  {  
     var originalBook=  _db.Books.FirstOrDefault(o => o.Id == id);
     _db.Entry(originalBook).CurrentValues.SetValues(book);
     _db.SaveChanges();
  }

Kindly note that you have to use EFcore version 1.1 for this to work

cpr43
  • 2,942
  • 1
  • 18
  • 18
  • It says `EntityEntry doesn't contain a definition for CurrentValues` also there is nothing to import when I mouseover – Thinker Mar 17 '17 at 08:51
  • it seems CurrentValues method is still not implemented in .net core , if you want you could use this(http://stackoverflow.com/questions/36369233/entity-framework-core-1-0-currentvalues-setvalues-does-not-exist) extension method – cpr43 Mar 17 '17 at 08:56
  • Okay, but it won't break any other dependencies right? I am absolutely new to ASP.net core development, rather this is my very first attempt! – Thinker Mar 17 '17 at 09:01
  • I have like this: "Microsoft.EntityFrameworkCore": "1.0.0", "MySql.Data.Core": "7.0.4-IR-191", "MySql.Data.EntityFrameworkCore": "7.0.6-IR31", – Thinker Mar 17 '17 at 09:03
  • make it "Microsoft.EntityFrameworkCore": "1.1.0" and run restore package – cpr43 Mar 17 '17 at 09:06
  • It gave me some error with MySql, so I am just restarting visual studio: `An exception of type 'System.IO.FileLoadException' occurred in Mysql_trial.dll but was not handled in user code` – Thinker Mar 17 '17 at 09:15
  • It threw this error in startup.cs on `services.AddDbContext(options =>{ options.UseMySQL(Configuration.GetConnectionString("SampleConnection"));});` – Thinker Mar 17 '17 at 09:18
  • try using other mysql providers like "Pomelo.EntityFrameworkCore.MySql" – cpr43 Mar 17 '17 at 09:23
  • Adding Pomelo.EntityFrameworkCore.MySql also gave me same error. Perhaps I will have to use different extensions like [Required] – Thinker Mar 17 '17 at 12:59
1

The simplest way, you just load book from the database. Update fields and save changes to the database.

Book existingBook = GetBook(id);
existingBook.Title = book.Title;
// other properties
_db.SaveChanges();
syned
  • 2,201
  • 19
  • 22
  • Isn't there any way to directly map somehow the fetched entity as per the id to the the received entity? Because not necessarily all the fields will be updated. – Thinker Mar 17 '17 at 08:49
  • 1
    you can use AutoMapper for mapping the fields. – syned Mar 17 '17 at 12:24
  • This answer works, however I am interested to see how `_db.Entry(originalBook).CurrentValues.SetValues(book);` will work in this case as it is eliminated the need to remember and specify the attributes while updating – Thinker Mar 17 '17 at 13:27
  • @Nitish I believe there should be the way to attach your new entity to the context as changed, so you can avoid loading the object first. I will try to find it. – syned Mar 19 '17 at 21:33
0

I think Update method should do what you want. High-level idea is to attach entity and set its state to modified which is exactly what Update method does.

// Make sure that Book id is set correctly.
book.Id = id;
_db.Books.Update(book);
_db.SaveChanges();
Andrii Litvinov
  • 12,402
  • 3
  • 52
  • 59