asp.net-mvc-4 - 在NHibernate中删除对象时出现“not-null property references a null or transient value”

标签 asp.net-mvc-4 nhibernate

我创建了一个 MVC 4 并使用 NHibernate 来保存模型并使用 Fluent nhibernate 映射它。该实体有一个“Name”属性,并按如下方式映射:

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

我创建了一个用于查看对象列表的表格,并允许我编辑、查看对象详细信息并删除它们。 当我删除对象时, View 层将模型 ID 发回到相应的 Controller ,并且 Controller 通过存储库对象尝试删除该对象。

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

表格 View 的部分内容:

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

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

因此 View 仅将 elemntID 回发到 Controller 。而元素对象只有它的ID。并且其所有属性均为 null。当由于 name 属性为 null 而尝试删除该对象时,存储库中的 session 对象无法删除该对象,因为 name 字段为 null。

错误消息:

not-null property references a null or transient value 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);
        }

最佳答案

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

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

当您将此对象传递给 NHibernate 时,它​​会注意到 session 没有观察到它并尝试附加它,这将看到大量脏属性值(全部为空),从而尝试刷新对其的更改首先。

您的操作应如下所示:

[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");
}

关于asp.net-mvc-4 - 在NHibernate中删除对象时出现“not-null property references a null or transient value”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19502476/

相关文章:

c# - ASP.NET Web API 性能问题

c# - 从虚拟目录下载文件

nhibernate - 在 NHibernate 中加载没有重复的多级集合

NHibernate HQL 按实体分组

c# - NHibernate 3 Alpha - proxyfactory.factory_class?

c# - 渴望在 NHibernate 中加载一棵树

c# - 如何在 ASP.NET MVC4 上打开 customErrors 模式?

jquery - 使用 knockout 提交后取消选中复选框列表

asp.net-mvc-4 - autofac - 依赖注入(inject)到 IHttpModule

c# - 我的项目不使用 NHibernate 是不是很愚蠢?