Сохранить сущность со связями в Entity Framework / ASP.NET MVC 2 - PullRequest
2 голосов
/ 29 сентября 2010

Я занимаюсь этим уже как минимум два дня.У меня нет книги, на которую можно ссылаться, и я не могу найти объяснение того, как это должно работать.

Я пытаюсь сделать простую операцию:

  1. Загрузить форму создания, заполненную тремя элементами выпадающего списка, которые ссылаются на другие таблицы
  2. Заполнить форму
  3. Отправить форму и сохранить объект

Я пытался всеми возможными способами заставить это работать.Это должно быть легко.Я пробовал это с и без ViewModel.Я думаю, что это будет понятнее без ViewModel

Примечание. Из-за требований я использую .NET 3.5.Означает ли это, что я использую старую версию EF?

Другое примечание: да, я использую VB.Нет, это не мой выбор.

Контроллер:

    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

Репозиторий:

Public Sub AddEscalation(ByVal esc As Escalation)
    esc.Created_At = DateTime.Now()
    entities.AddToEscalations(esc)
End Sub

Public Sub Save()
    entities.SaveChanges()
End Sub

Вид:

        <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>

При использовании DropDownListFor ... model.Property происходит сбой при вызове TryUpdateModel.Ошибки проверки выглядят так в возвращаемой форме: Недопустимое значение 35.

Если я изменю его на DropDownListFor ... model.Property.Id, оно умирает на SaveChanges() примерно так:

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. 

При отладке у моего Escalation есть Category, с заполненным только свойством Id и находящимся в состоянии Detached.

Если я заполняю следующееполные объекты:

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

Я получаю: сущности в 'Escalations_Conn.Paths' участвуют в отношениях 'FK_Paths_Categories'.0 связанных "Категория" были найдены.1 «Категория» ожидается.

Я очень ценю любую помощь, которую кто-либо имеет.

Ответы [ 3 ]

2 голосов
/ 29 сентября 2010

Таким образом, проблема заключается в том, что вы привязываете только идентификатор вашей категории Escalation.Category, а не само имя. Обычно правильный подход заключается в использовании идентификатора для фактического получения категории и игнорирования привязки к вложенному свойству.

  If TryUpdateModel(escalation, <use ignore overload to ignore the category property>) Then
        Dim existingCategory = repo.GetCategoryById( escalation.Category.Id )
        escalation.Category = existingCategory
        repo.AddEscalation(escalation)  
        repo.Save()
        Return RedirectToAction("Details", New With {.Id = escalation.Id})
    End If

Другой альтернативой является присоединение связанной Категории к ObjectContext, чтобы его состояние было установлено правильно, а значения его имен были гидратированы.

    If TryUpdateModel(escalation, <use ignore overload to ignore the category property>) Then

        repo.Attach(escalation.Category, "Categories" )            

        repo.AddEscalation(escalation)  
        repo.Save()
        Return RedirectToAction("Details", New With {.Id = escalation.Id})
    End If

Поскольку я не использую регулярность VB и не знаю, что такое репо, приведенный выше код следует рассматривать как псевдокод, и вам, возможно, придется поискать в документации правильные перегрузки для использования.

1 голос
/ 30 сентября 2010

Я ценю всю помощь, которую мне оказали.

После долгих копаний, я считаю, что проблема в том, что я использую EF1, потому что я на .NET 3.5. Я знаю, что Linq to SQL отчасти устарел, но для .NET 3.5 я уверен, что он намного лучше, чем EF1. Поэтому я переключил свой проект на использование Linq для SQL. И это работает именно так, как я себе представляю. Я просто привязываю свою форму к внешнему ключу:

<%= Html.DropDownListFor(Function(model) model.Category_Id, 
  New SelectList(ViewData("categoryList"), "Id", "Name"))%>

И вуаля! Модель экономит с правильными ассоциациями!

1 голос
/ 29 сентября 2010

нельзя просто использовать ModelState.IsValid вместо TryUpdateModel, который я всегда использовал в своих результатах редактирования действий.в отладочной проверке, какой ключ Modelstate содержит ошибку.Вы также можете проверить метаданные, которые прикреплены к модели Escalation, чтобы проверить источник ошибки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...