NHibernate的使用级联更新相当的简单,但今天在使用的时候却碰到一个错误,在更新对象的一个关联对象时报错:A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance
这个问题出现的字面意思是,我们使用了级联更新:all-delete-orphan,但是遗憾的是,使用的Collection所在的宿主对象不再能得到引用,因此导致更新失败。既然是这样就看看引用了,在出错的代码处,代码如下:
public void SaveModel(Product model)
{
/*some logic code.*/
var p = _pRepository.Get(model.id);
/* 这里设置了需要删除的分类id:tc_delete_id和需要更新的分类Id:tc_update_id*/
IList<PT> need_to_update = (from t in p.PTList
where t.Category.Id == tc_update_id
select t).ToList();
IList<PT> need_to_add = GetNeedAddList();
p.PTList.Clear();
p.PTList = need_to_update.Union(need_to_add).ToList();
_pRepository.Update(p);
}
代码中就是对p中的PTList进行更新而已,而PTList就是报错中出现的不能更新的那个对象,设置的是all-delete-orphan关系。这么看没有任何问题,因为需要删除的列表不好提取,就直接将需要更新的取出来,在添加上需要新增的列表,最后将结果导入到PTList中。
网上查找很多都是莫名其妙的解决方法, 当然,大多数还是Hibernate的,而不是NHibernate的,作为NHibernate的新手,对此总是有那么点丈二和尚——摸不着头,所以一切还得自己来。
看报错,应该就是PTList的引用出问题了,也许你在用NHibernate的刚开始碰到过如下操作:
var p = _pRepository.Get(model.id);
_pRepository.Update(model);
我比较愚钝,这个错误被我犯过,系统会报在Session中已经有一个对象了,所以导致Update失败。
为什么要说这个呢,我感觉应该是差不多的逻辑,应该是NHibernate对于在Session内的对象会进行维护,而但我们操作的时候,一旦用新的对象(NHibernate已经维护一份)来替换NHibernate维护的那份时,如果没有适当的操作,应该就会报错了。
既然是这个想法,那么让我们来试试吧:
在p.PTList.Clear();后面添加上:
Session.Clear(); // 这个是清除所有Session中的缓存。
运行吧,奇迹诞生了,没有报错了,看来猜想是对的。不过等等,不要高兴的太早了,你会发现系统竟然没有删除我们要删除的内容?!这个缓存清除,让系统无法知晓那些对象该删除了。这个不是我们想要的。看来我们猜想是对的,不过,操作起来却不能这样。
既然这样,我们就好好的让NHibernate来维护这个关系吧。换种思路,虽然艰难了一点,寻找出需要删除的对象:
IList<PT> need_to_delete = (from t in p.PTList
where t.Category.Id == tc_delete_id
select t).ToList();
然后将PTList中的这些对象删除掉。之后,添加需要的对象。再来更新,问题得到解决。
这是一次浅尝辄止的摸索,对于NHibernate的菜鸟来说,暂时还没有更好的方法来解决,如果你有,请告诉我。