I have been dealing with this for at least two days now. I don’t have a book available to reference, and I cannot for the life of me find an explanation of how this is supposed to work.
What I am trying to do is a simple operation:
- Load a create form populated with 3 dropdownlist elements which reference other tables
- Fill out the form
- Submit the form and save the entity
I have tried every way I can think of to get this to work. This should be easy. I have tried it with and without a ViewModel. I think it’s clearer without the ViewModel
Note: Due to requirements, I am using .NET 3.5. Does this mean I am on an older version of EF?
Another Note: Yes, I am using VB. No, that is not my choice.
Controller:
Function Create() As ActionResult
PopulateForm()
Return View()
End Function
<HttpPost()>
Function Create(ByVal escalation As Escalation) As ActionResult
If TryUpdateModel(escalation) Then
repo.AddEscalation(escalation)
repo.Save()
Return RedirectToAction("Details", New With {.Id = escalation.Id})
End If
'The model did not save - there are validation errors'
PopulateForm()
Return View()
End Function
Private Sub PopulateForm()
ViewData("categoryList") = repo.GetAllCategories().ToList()
ViewData("statusList") = repo.GetAllStatuses().ToList()
ViewData("pathList") = New List(Of Path)
End Sub
Repository:
Public Sub AddEscalation(ByVal esc As Escalation)
esc.Created_At = DateTime.Now()
entities.AddToEscalations(esc)
End Sub
Public Sub Save()
entities.SaveChanges()
End Sub
View:
<div class="editor-label">
<%= Html.LabelFor(Function(model) model.Status)%>
</div>
<div class="editor-field">
<%= Html.DropDownListFor(Function(model) model.Status, New SelectList(ViewData("statusList"), "Id", "Name"))%>
<%= Html.ValidationMessageFor(Function(model) model.Status)%>
</div>
<div class="editor-label">
<%= Html.LabelFor(Function(model) model.Category)%>
</div>
<div class="editor-field">
<%= Html.DropDownListFor(Function(model) model.Category, New SelectList(ViewData("categoryList"), "Id", "Name"))%>
<%= Html.ValidationMessageFor(Function(model) model.Category)%>
</div>
When using the DropDownListFor… model.Property, it fails in the TryUpdateModel call. The validation errors look like this in the returned form: The value ’35’ is invalid.
If I change it to DropDownListFor…model.Property.Id, it dies on SaveChanges() like so:
Cannot insert the value NULL into column 'Name',
table 'Escalations_Dev.dbo.Categories';
column does not allow nulls. INSERT fails.
The statement has been terminated.
In debugging, my Escalation does have a Category, with only the Id property populated and in the Detached state.
If I do the following to populate the full objects:
Public Sub AddEscalation(ByRef esc As Escalation)
esc.Created_At = DateTime.Now()
esc.Category = Me.GetCategory(esc.Category.Id)
esc.Status = Me.GetStatus(esc.Status.Id)
esc.Path = Me.GetPath(esc.Path.Id)
entities.AddToEscalations(esc)
End Sub
Public Function GetPath(ByVal id As Integer) As Path
Dim path As Path = entities.Paths.FirstOrDefault(Function(c) c.Id = id)
path.CategoryReference.Load()
Return path
End Function
I get: Entities in ‘Escalations_Conn.Paths’ participate in the ‘FK_Paths_Categories’ relationship. 0 related ‘Category’ were found. 1 ‘Category’ is expected.
I really appreciate any help anyone has.
I appreciate all the help I was given.
After a lot of digging, I believe the problem is that I’m using EF1 because I’m on .NET 3.5. I know Linq to SQL is kind of deprecated, but for .NET 3.5 I’m pretty sure it is far better than EF1. As such, I’ve switched my project to use Linq to SQL. And it works exactly like I would imagine. I just bind my form to the foreign key:
And voila! The model saves with the correct associations!