2010-09-29 53 views
2

我一直在處理這個問題至少兩天了。我沒有一本可供參考的書,而且我不能在我的生活中找到解釋該如何工作的解釋。在實體框架/ ASP.NET MVC中保存具有關係的實體2

我所試圖做的是一個簡單的操作:

  1. 加載一個創建表格填入3下拉列表元素,其引用其他表
  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. 

在調試時,我的升級確實有一個類別,只有編號財產填充和分離狀態。

如果我做了以下填充完整的對象:

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'類別'預計。

我真的很感謝任何人的幫助。

+1

好的,那麼你得到的錯誤/結果是什麼? – 2010-09-29 15:54:09

+0

對不起,我在底部添加了更多關於結果的詳細信息。 – ItsJason 2010-09-29 16:08:39

回答

1

我感謝所有給予我的幫助。

經過大量的挖掘,我相信問題是我使用EF1,因爲我在.NET 3.5上。我知道Linq to SQL是不贊成使用的,但對於.NET 3.5,我相當肯定它比EF1好得多。因此,我已經將我的項目轉換爲使用Linq to SQL。它和我想象的完全一樣。我只是將我的表格綁定到外鍵:

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

瞧!該模型保存正確的關聯!

1

不能只使用ModelState.IsValid而不是TryUpdateModel,我總是用我的編輯actionresults。在調試時檢查Modelstate的哪個鍵包含錯誤。你也可以檢查附加到升級模型的元數據來檢查錯誤的來源

+0

感謝穆罕默德, ModelState.IsValid()返回false,我相信,相同的問題TryUpdateModel()有: 消息\t「的參數轉換,從類型‘System.String’輸入‘EscalationTool.Category’失敗,因爲沒有類型轉換器可以在這些類型之間轉換。「 這就是爲什麼我試圖改變形式來引用Model.Category.Id來代替。 – ItsJason 2010-09-29 17:18:22

+0

你沒有字段Escalation.CategoryID,其中類別id將是數據庫中引用類別表的實際外鍵。如果是這樣,你應該改變類型爲Escalation.categoryID。 – 2010-09-29 17:24:46

+0

我也這麼認爲,但是當我使用.NET 3.5時,外鍵不會作爲屬性公開。如果我在4.0版本上,也許這將是解決方案,並且由於我不在4.0版本中,我不得不使用一些不合理的解決方法? – ItsJason 2010-09-29 17:31:04

2

所以問題在於你只綁定了你的Escalation.Category的ID而不是名稱本身。通常,正確的方法是使用Id實際獲取類別並忽略綁定嵌套屬性。

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規律,我不知道什麼是回購上述代碼應被視爲僞代碼,你可能要看看文檔中正確的重載使用。

+0

謝謝jfar。我無法使TryUpdateModel的ExcludeProperties部分正常工作,但我確實完成了您所建議的其餘部分。我已經添加到顯示結果的問題的底部。 – ItsJason 2010-09-29 19:52:44

+0

@coderj,稍後我會試着幫忙,關閉一下,但我確切地知道最新的錯誤 – jfar 2010-09-29 20:05:10