2013-10-21 68 views
2

我創建了一個MVC 4並使用NHibernate來持久化模型並將其與流暢的nhibernate進行映射。實體有一個「名稱」屬性和映射像這樣:在NHibernate中刪除一個對象時,「非空屬性引用一個空值或瞬態值」

Map(x => x.Name).Not.Nullable().Length(100); 

我創建了一個表,觀察對象名單,讓我來編輯,查看對象的詳細信息,並刪除它們。 當我刪除對象時,視圖層通過存儲庫對象將模型Id回發給相應的控制器和控制器,嘗試刪除該對象。

[HttpPost] 
    public ActionResult DeleteElement(Element element) 
    { 
     Element deletedElement = repository.Delete(element); 
     TempData["message"] = string.Format("{0} has been deleted.",deletedElement.Name); 
     return RedirectToAction("Index"); 
    } 

局部表視圖:

<td> 
      @using (Html.BeginForm("DeleteMenu", "Admin")) 
      { 
       @Html.Hidden("ID", item.ID) 

       <input type="submit" value="Delete"/> 
      } 
     </td> 

所以視圖只發布回elemntID到控制器。元素對象只有它的ID。並且它的所有屬性都爲null。當試圖刪除對象是因爲name屬性爲null時,存儲庫中的會話對象無法刪除對象,因爲name字段爲空。

錯誤消息:

非空屬性引用null或瞬時值Element.Name

如果我只是刪除對象,並有主鍵,爲什麼如果其他字段爲空,nHibernate會關心嗎? 以及如何刪除對象只有它的ID?

public IQueryable<T> GetAll() 
    { 
     return session.Query<T>(); 
    } 

    public IQueryable<T> Get(Expression<Func<T, bool>> predicate) 
    { 
     return GetAll().Where(predicate); 
    } 


public void Delete(T entity) 
     { 
      session.Delete(entity); 
     } 

回答

2

從NHibernate的檢索實例第一,並使用該作爲對象通入Delete

發生什麼事是你正在NHibernate的權限之外創建一個對象(在MVC模型綁定中)。由於您只是在HTML表單中指定了標識,因此模型聯編程序完成時模型的屬性也全爲空。

當你將這個對象傳遞給NHibernate時,它會注意到它沒有被會話觀察到並嘗試附加它,這會看到很多髒屬性值(全爲空),因此試圖將更改刷新到它首先。

你的行動應該是這樣的:

[HttpPost] 
public ActionResult DeleteElement(int id) 
{ var element = repository.Get(e => e.Id == id).First(); 
    repository.Delete(element); 

    TempData["message"] = string.Format("{0} has been deleted.",deletedElement.Name); 
    return RedirectToAction("Index"); 
} 

我會建議添加到您的資料庫,通過NHibernate的包裝Load的方法。 Load非常有用,因爲它使用您指定的ID創建對象的觀察實例,但在訪問ID以外的屬性之前實際上不會訪問數據庫。這對於知道對象存在的情況非常有用,但只需要一個指針(例如刪除一個實體或將其添加到關係中)。

更新資料庫:

public IQueryable<T> GetAll() 
{ 
    return session.Query<T>(); 
} 

public IQueryable<T> Get(Expression<Func<T, bool>> predicate) 
{ 
    return GetAll().Where(predicate); 
} 

public T DeferredGet(int id) // I like to call it DeferredGet, you can call it Load or whatever you want 
{ 
     return session.Load<T>(id); 
} 

public void Delete(T entity) 
{ 
    session.Delete(entity); 
} 

,然後你的最新行動:

[HttpPost] 
public ActionResult DeleteElement(int id) 
{ var element = repository.DeferredGet(id); // will not actually hit the database, saving you a query. 
    repository.Delete(element); // deletes the element normally. 

    TempData["message"] = string.Format("{0} has been deleted.",deletedElement.Name); 
    return RedirectToAction("Index"); 
} 
+0

感謝。你的詳細答案幫了很大忙,問題就解決了。 –

相關問題