I am having difficulty getting a nested collection (Tags in my case) to commit back to the database after being passed into my controller. I am using EF 4.1 with the DbContext API, MVC 3, and Automapper.
My Models:
Partial Public Class Proposal
Public Property Id As Integer
Public Property Memo As String
Public Property EntryDate As Nullable(Of Date)
Public Overridable Property CategoryTags As ICollection(Of CategoryTag) = New HashSet(Of CategoryTag)
End Class
Public Class ProposalViewModel
Public Property Id As Integer
<DataType(DataType.MultilineText)>
Public Property Memo As String
<DisplayFormat(ApplyFormatInEditMode:=True, DataFormatString:="{0:d}")>
Public Property EntryDate As Nullable(Of Date)
Public Overridable Property CategoryTags As ICollection(Of CategoryTag) = New HashSet(Of CategoryTag)
End Class
My view uses the code from the following post to add tags: http://jarrettmeyer.com/post/2995732471/nested-collection-models-in-asp-net-mvc-3. Essentially the tags are created by adding INPUT elements with their name attribute set to "CategoryTag[0].Id", "CategoryTag[1].Id" etc... and the value of those inputs are valid Ids for Tags in my database
Lastly, my POST code:
<HttpPost()>
Public Function Edit(ByVal pvm As ProposalViewModel) As ActionResult
Dim p As New Proposal
p = AutoMapper.Mapper.Map(Of ProposalViewModel, Proposal)(pvm)
If (ModelState.IsValid) Then
db.Entry(p).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
Else
Return View(pvm)
End If
End Function
The pvm object is returned to my controller with the values set as I would want them to be. If I add two tags in run-time, then it has two CategoryTag objects in it's collection with the appropriate IDs. The problem is that on my call to SaveChanges, the corresponding records a开发者_如何学Gore not created in my many-to-many relation table (ProposalCategoryTag in this case).
Any idea what I'm doing wrong?
UPDATE:
I did not find anything on this, and have resorted to doing it manually like below. I dislike this method, but it works.
<HttpPost()>
Public Function Edit(ByVal pvm As ProposalViewModel) As ActionResult
Dim p As New Proposal
Dim tempTag As CategoryTag
p = AutoMapper.Mapper.Map(Of ProposalViewModel, Proposal)(pvm)
If (ModelState.IsValid) Then
db.Proposals.Attach(p)
db.Entry(p).Collection("CategoryTags").Load()
For Each ct As CategoryTag In pvm.Tags
tempTag = db.CategoryTags.Find(ct.Id)
If tempTag Is Nothing Then
Continue For
End If
If p.CategoryTags.Contains(tempTag) Then
Continue For
End If
p.CategoryTags.Add(tempTag)
Next
db.Entry(p).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
Else
Return View(pvm)
End If
End Function
UPDATE:
I did not find anything on this, and have resorted to doing it manually like below. I dislike this method, but it works.
<HttpPost()>
Public Function Edit(ByVal pvm As ProposalViewModel) As ActionResult
Dim p As New Proposal
Dim tempTag As CategoryTag
p = AutoMapper.Mapper.Map(Of ProposalViewModel, Proposal)(pvm)
If (ModelState.IsValid) Then
db.Proposals.Attach(p)
db.Entry(p).Collection("CategoryTags").Load()
For Each ct As CategoryTag In pvm.Tags
tempTag = db.CategoryTags.Find(ct.Id)
If tempTag Is Nothing Then
Continue For
End If
If p.CategoryTags.Contains(tempTag) Then
Continue For
End If
p.CategoryTags.Add(tempTag)
Next
db.Entry(p).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
Else
Return View(pvm)
End If
End Function
精彩评论