本节内容
- 概览
- 实例
- 分析
这个系列是以博客形式整理关于NHibernate的Issues。记录一些零碎的小例子,通过零零碎碎的整理,可以巩固自己的知识和扩展我们的知识面。这些小例子也可以适当的在项目中呈现。
这次看看ISession.SaveOrUpdateCopy()方法。
实例这个小例子可以分析到这个方法的使用。
1.Domain定义一Domain,关联一些字典。
public class Parent { public virtual int Id { get; set; } public virtual IDictionary<Key, Value> Relations { get; set; } } public enum Key { One, Two } public enum Value { ValOne, ValTwo }2.Mapping
使用Map映射字典类型,在RelationsTable表中,级联所有和删除孤单节点。
<class name="Parent"> <id name="Id"> <generator class="assigned" /> </id> <map name="Relations" table="RelationsTable" cascade="all-delete-orphan"> <key column="ParentID" /> <index column="KeyId" type="Key" /> <element column="Value" type="Value" /> </map> </class>3.Test
在第一个Session中保存这个Domain,在第二个Session中获取这个Domain并关闭销毁这个Session,在第三个Session中保存或者更新复制这个Domain。
using (var session = OpenSession()) { var entityDomain = new Parent { Id = 1, Relations = new Dictionary<Key, Value> { {Key.One, Value.ValOne}, {Key.Two, Value.ValTwo} } }; session.Save(entityDomain); session.Flush(); } Parent entity; using (var session = OpenSession()) { entity = session.Get<Parent>(1); session.Close(); session.Dispose(); } using (var session2 = OpenSession()) { entity = (Parent)session2.SaveOrUpdateCopy(entity); }4.结果
看看上面测试输出的SQL语句吧,一清二楚:
--插入数据 INSERT INTO Parent (Id) VALUES (@p0);@p0 = 1 INSERT INTO RelationsTable (ParentID, KeyId, Value) VALUES (@p0, @p1, @p2);@p0 = 1, @p1 = 0, @p2 = 0 INSERT INTO RelationsTable (ParentID, KeyId, Value) VALUES (@p0, @p1, @p2);@p0 = 1, @p1 = 1, @p2 = 1 --ISession.Get()方法 SELECT parent0_.Id as Id0_0_ FROM Parent parent0_ WHERE parent0_.Id=@p0;@p0 = 1 --ISession.SaveOrUpdateCopy()方法 SELECT parent0_.Id as Id0_0_, relations1_.ParentID as ParentID2_, relations1_.Value as Value2_, relations1_.KeyId as KeyId2_ FROM Parent parent0_ left outer join RelationsTable relations1_ on parent0_.Id=relations1_.ParentID WHERE parent0_.Id=@p0;@p0 = 1分析
在NHibernate API文档中对ISession.SaveOrUpdateCopy()方法这样的解释:
简单的就是说:将传入的对象的状态也就是属性赋给Session缓存中相同键值的对象上,如果该对象不存在则从数据库加载,传入的对象并不进行持久化。如果数据库不存在这个对象,则进行保存。
所以,当我们调用ISession.SaveOrUpdateCopy()方法时,先把传的对象赋值到新的对象(如果传的参数为空,则抛出“attempt to create merge event with null entity”异常),然后发出一条SQL查询数据库:
- 数据库里有这个对象并相同,什么都不做。
- 数据库里有这个对象,其属性改变了,就发送SQL更新数据库
- 数据库没有这个对象,则保存这个对象到数据库。
我想这样做的目的就是保证对象的原子性,不可能别人已经动过数据库了,你还拿一个脏对象来操作。大家可以修改上面的代码测试一下。
那么ISession.SaveOrUpdateCopy()方法在哪里使用呢?
在Web程序中应该没什么用处,因为我们常常使用session-per-request策略,请求之后Session就关闭了也没什么用了。但是在WPF程序中,经常在几个Session中操作对象,操作不慎,会出现各种各样的异常。比如我们如何把这个对象从一个Session中附加到另外一个Session中持久化使用呢。