I have the two entities, Arena and Regulator, which have a many to many relationship between them. I have implemented what seems to be the EF code first accepted solution (
After a lot of research I have understood that EF cannot update relationships - very surprising and disappointing. Aparently, the suggested solution is a manual update of the join table and navigation properties - not very good. NHibernate apparently does do this out of the box and I fully intend to investigate next time I need this.
Luckily I came across a truly great solution from Refactor(This) that adds an extension method to DbContext, allowing automated updating of complex relationships. There is even a Nuget package!
So here is my full solution:
I've added an integer list to the Regulator class, which gets the IDs of the selected Arenas.
Public Class Regulator
Public Property Id As Integer
Public Property Name As String
Public Property ArenaIDs() As ICollection(Of Integer)
Public Overridable Property Arenas() As ICollection(Of Arena)
End Class
In the GET Edit action, this is taken care of and a MultiSelectList is created:
' GET: /Regulator/Edit/5
Function Edit(Optional ByVal id As Integer = Nothing) As ActionResult
Dim regulator As Regulator = db.Regulators.Find(id)
If IsNothing(regulator) Then
Return HttpNotFound()
End If
For Each a In regulator.Arenas
regulator.ArenaIDs.Add(a.Id)
Next
ViewBag.MultiSelectArenas = New MultiSelectList(db.Arenas.ToList(), "Id", "Name", regulator.ArenaIDs)
Return View(regulator)
End Function
And the MultiSelectList is used in the View:
@Html.ListBoxFor(Function(m) m.ArenaIDs, ViewBag.MultiSelectArenas)
@Html.ValidationMessageFor(Function(model) model.Arenas)
In the POST Edit action the selection IDs are retrieved and used to update the Arenas collection. Then the magic comes in the with the UpdateGraph extension method that does what EF can not and updates the relationship!
' POST: /Regulator/Edit/5
_
_
Function Edit(ByVal regulator As Regulator) As ActionResult
If ModelState.IsValid Then
For Each i In regulator.ArenaIDs
regulator.Arenas.Add(db.Arenas.Find(i))
Next
db.UpdateGraph(Of Regulator)(regulator, Function(map) map.AssociatedCollection(Function(r) r.Arenas))
db.SaveChanges()
Return RedirectToAction("Index")
End If