“非空属性引用null或瞬时值”删除NHibernate的对象时 [英] “not-null property references a null or transient value” when deleting an object in NHibernate

查看:247
本文介绍了“非空属性引用null或瞬时值”删除NHibernate的对象时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经创建了一个MVC 4并使用NHibernate的持久化模型和功能NHibernate映射它。实体具有名称属性,以这种方式映射的像

 地图(X => x.Name)。.Not.Nullable()长度(100);

我创建了一个表,观察对象名单,让我来编辑,查看对象的详细信息并将其删除。
当我删除对象的视图层后回模型ID,通过库对象相应的控制器和控制器尝试删除对象。

  [HttpPost]
    公众的ActionResult DeleteElement(元元)
    {
        元素deletedElement = repository.Delete(元素);
        TempData的[消息] =的String.Format({0}已被删除。deletedElement.Name);
        返回RedirectToAction(「指数」);
    }

偏表视图:

 < TD>
            @using(Html.BeginForm(DeleteMenu,管理))
            {
                @ Html.Hidden(ID,item.ID)                <输入类型=提交值=删除/>
            }
        < / TD>

因此​​认为只发布回elemntID控制器。和元素对象只有其ID。和它的所有属性都null.when试图删除对象,因为name属性为null,因为name字段为空资源库中的会话对象不能删除的对象。

错误消息:


  

非空属性引用null或瞬时值Element.Name


如果我只是删除对象,并有主键,为什么NHibernate的关心,如果其他字段为空?
以及如何我只用它的ID删除对象?

 公开的IQueryable< T>得到所有()
    {
        返回session.Query< T>();
    }    公众的IQueryable< T>获取(前pression<&Func键LT; T,BOOL>> predicate)
    {
        返回GETALL()式(predicate)。
    }
 公共无效删除(T实体)
        {
            使用Session.delete(实体);
        }


解决方案

首先检索从NHibernate的实例,并使用的的作为对象传递到删除

这是怎么回事是要创建NHibernate的范围以外的对象(在MVC模型绑定)。由于您指定的HTML表单只不过是ID,模型的属性均为空当模型绑定完成了。

当你通过这个对象NHibernate的,它会发现,它不是由会话观察,并尝试将其附着,这会看到很多肮脏的属性值(全空),从而尝试刷新更改它第一位。

您的行动应该是这样的:

  [HttpPost]
公众的ActionResult DeleteElement(INT ID)
{VAR元= repository.Get(E => e.Id == ID)。首先();
    repository.Delete(元件);    TempData的[消息] =的String.Format({0}已被删除。deletedElement.Name);
    返回RedirectToAction(「指数」);
}

我会建议添加到您的仓库里的方法,通过NHibernate的包装加载。因为它会用指定的ID对象的观察实例,但实际上并没有触及数据库中,直到您访问比其它ID属性加载是非常有用的。它是在哪里你知道对象存在的情况下非常有用,但只需要一个指针(如删除一个实体,或在关系添加它)。

更新资料库:

 公开的IQueryable< T>得到所有()
{
    返回session.Query< T>();
}公众的IQueryable< T>获取(前pression<&Func键LT; T,BOOL>> predicate)
{
    返回GETALL()式(predicate)。
}公共ŧDeferredGet(INT ID)//我喜欢把它称为DeferredGet,你可以称之为负载或任何你想要的
{
       返回session.Load< T>(ID);
}公共无效删除(T实体)
{
    使用Session.delete(实体);
}

,然后更新的动作:

  [HttpPost]
公众的ActionResult DeleteElement(INT ID)
{VAR元= repository.DeferredGet(ID); //实际上不会访问数据库,节省您的查询。
    repository.Delete(元件); //通常会删除的元素。    TempData的[消息] =的String.Format({0}已被删除。deletedElement.Name);
    返回RedirectToAction(「指数」);
}

I have created an MVC 4 and use NHibernate for persisting the model and mapped it with fluent nhibernate. the entity has a "Name" property and mapped like in this way:

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

I have created a table for viewing the list of objects and let me to edit, view object details and delete them. when I delete the object it the view tier post back the model Id to the corresponding controller and controller via the repository object tries to delete the object.

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

the partial of table view:

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

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

So the view only post back the elemntID to the controller. and element object has only its ID. and all of its properties are null.when trying to delete the object because the name property is null, the session object in the repository can't delete the object because name field is null.

the Error message:

not-null property references a null or transient value Element.Name

If I am only removing an object and have the primary key, why does nHibernate care if other fields are null? and how can I delete the object only with its 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);
        }

解决方案

Retrieve the instance from NHibernate first, and use that as the object to pass into Delete.

What is happening is you are creating an object outside of NHibernate's purview (in the MVC model binding). Since you are specifying nothing but the ID in the HTML form, the model's properties are all null when the model binder finishes, too.

When you pass this object to NHibernate, it will notice that it is not being observed by the session and try to attach it, which will see lots of dirty property values (all nulls), and thus try to flush changes to it first.

Your action should look like this:

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

I would recommend adding a method to your repository that wraps Load by NHibernate. Load is useful because it creates an observed instance of the object with the ID you specify, but does not actually hit the database until you access a property other than the ID. It's very useful for situations where you know the object exists, but only need a pointer (such as deleting an entity, or adding it in a relationship).

Updated repository:

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

and then your updated action:

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

这篇关于“非空属性引用null或瞬时值”删除NHibernate的对象时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆