简体   繁体   中英

ASP MVC Entity Framework core. Update many to many relationship on form post

I'd like to know a good practice to update a many to many relationship when submit form.

I got these two entities and I use the default many to many relationship from EF core 5:

public class BlogEntry
   {
      public int Id { get; set; }
      [Required]
      [MaxLength(200)]
      public string Title { get; set; }
      [Required]
      public string EntryText { get; set; }
      [NotMapped] 
      public IEnumerable<string> CategoriesToPublish { get; set; } 
      public ICollection<Category> Categories { get; set; } 

   }
   public class Category
   {
      public int Id { get; set; }
      public string Name { get; set; }
      public ICollection<BlogEntry> BlogEntries { get; set; }
   }

context:

      public DbSet<BlogEntry> BlogEntries { get; set; }
      public DbSet<Category> Categories { get; set; }

And I have a form witha multiselect field to represent this relationship. See Image form

I'm not using the relation property on the form(maube I should, but I don't know), I have another property to convert the relationship into a list of strings called CategoriesToPublish so I can load the multiselect and retrieve the selection on post.

On the post action method, I want to iterate the this CategoriesToPublish and update all the relationships.

      [HttpPost]
      [ValidateAntiForgeryToken]
      public async Task<IActionResult> Publish(BlogEntry blogEntry)
      {
         if (ModelState.IsValid)
         {
            blogEntry.Categories = await _context.Categories.Where(x => x.BlogEntries.Any(x => x.Id == blogEntry.Id)).ToListAsync();
            await UpdateCategories(blogEntry);
            _context.Update(blogEntry);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(List));
         }
         return View(blogEntry);
      }

But the problem that I'm facing is that the Categories relationship is not loaded on postback. And if I try to load it manually and save context, I get an error saying SqlException: Violation of PRIMARY KEY constraint 'PK_BlogEntryCategory'. Cannot insert duplicate key in object 'dbo.BlogEntryCategory' SqlException: Violation of PRIMARY KEY constraint 'PK_BlogEntryCategory'. Cannot insert duplicate key in object 'dbo.BlogEntryCategory'

I am not sure how to approach this problem. Any advice?

After lot of searching I found out a solution.

      [HttpPost]
      [ValidateAntiForgeryToken]
      public async Task<IActionResult> Publish(BlogEntry blogEntry)
      {
         if (ModelState.IsValid)
         {
            blogEntry = _context.Update(blogEntry).Entity;
            blogEntry.Categories = await _context.Entry(blogEntry).Collection(u => u.Categories).Query().ToListAsync();
            await UpdateCategories(blogEntry);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(List));
         }
         return View(blogEntry);
      }

I retrieve the blogEntry after Update :

blogEntry = _context.Update(blogEntry).Entity;

At this point the Categories are still empty, but now we can load them from DB again:

blogEntry.Categories = await _context.Entry(blogEntry).Collection(u => u.Categories).Query().ToListAsync();

and boila, now we are good to iterate all the Categories change them if needed, it doesn't complain about duplicate keys.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM