【问题标题】:“not-null property references a null or transient value” when deleting an object in NHibernate在 NHibernate 中删除对象时,“非空属性引用空值或瞬态值”
【发布时间】:2013-10-30 09:57:15
【问题描述】:

我创建了一个 MVC 4 并使用 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。并且它的所有属性都是空的。当由于名称属性为空而尝试删除对象时,存储库中的会话对象无法删除该对象,因为名称字段为空。

错误信息:

not-null 属性引用了一个 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);
        }

【问题讨论】:

    标签: asp.net-mvc-4 nhibernate


    【解决方案1】:

    首先从 NHibernate 中检索实例,并使用 that 作为传递给Delete 的对象。

    正在发生的事情是您正在 NHibernate 的权限范围之外创建一个对象(在 MVC 模型绑定中)。由于您在 HTML 表单中只指定了 ID,因此当模型绑定器完成时,模型的属性也全部为空。

    当你将此对象传递给 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 包装 LoadLoad 很有用,因为它使用您指定的 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");
    }
    

    【讨论】:

    • 谢谢。您的详细回答帮助很大,问题也轻松解决了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 1970-01-01
    • 2017-04-25
    • 1970-01-01
    • 2016-11-26
    相关资源
    最近更新 更多