日期:2009-07-31  浏览次数:20492 次

当持久化对象时,显然必须存在把记录的值赋值到对象属性和取得对象属性的值用于持久化操作,对于更新操作,还需要检查对象的值是否已发生变化,即是否为Dirty,这些操作都是由对象的持久化类来完成的。有关持久化类可参考《会话和持久化操作》一文。


下面对NH的源码进行分析,以了解NH中数据加载和更新的过程。

一、持久对象加载

先来想像一下对象的加载过程(Load).
1. 根据对象Id从数据库取得记录;
2. 使用默认的构造函数构造一个对象;
3. 把记录的值存储在一个地方,用于在保存时进行比较;
4. 把记录的值赋值给对象的属性。

在本文的前篇中已经分析了对象加载过程的前半部分,这里仅对后半部分进行分析。

//*** EntityLoader.cs 34行 ***
public object Load(ISessionImplementor session, object id, object obj) {
   IList list = LoadEntity(session, new object[] { id }, idType, obj, id, false);
   if (list.Count==1) {
      return list[0];
   }
   else if (list.Count==0) {
      return null;
   }
   else {
      throw new HibernateException( "..." );
   }
}
当使用Session.Load加载对象时,最后将调用对象持久化类的Load方法。

//*** Loader.cs 745行 ***
protected IList LoadEntity( ISessionImplementor session,
   object[] values, IType[] types, object optionalObject,
   object optionalID, bool returnProxies) {
    return DoFind(session, values, types, optionalObject,
      optionalID, null, null, returnProxies, null, null, null);
}
直接调用DoFind。

private IList DoFind(
   ISessionImplementor session, object[] values,
   IType[] types, object optionalObject,
   object optionalID, PersistentCollection optionalCollection,
   object optionalCollectionOwner, bool returnProxies,
   RowSelection selection, IDictionary namedParams,
   IDictionary lockModes) {

   // 取得要加载的持久对象类型,有些查询只取某些属性的值,这时Persisters是空集合。
   ILoadable[] persisters = Persisters;
   int cols = persisters.Length;
   bool returnsEntities = cols > 0; // 判断是否要返回实体(持久对象)

   ArrayList hydratedObjects = returnsEntities ? new ArrayList() : null;

   Key optionalObjectKey;
   if (optionalObject!=null) {
      optionalObjectKey = new Key(optionalID, session.GetPersister(optionalObject) );
   }
   else {
      optionalObjectKey = null;
   }

   IList results = new ArrayList();

   IDbCommand st = null;

   // 解析查询字符串并生成IDbCommand.
   st = PrepareCommand(
      ApplyLocks(SqlString, lockModes, session.Factory.Dialect),
      values, types, namedParams, selection, false, session);

   IDataReader rs = GetResultSet(st, selection, session);

   try {
      Key[] keys = new Key[cols];

      // 开始处理结果集.
      int count;
      for ( count=0; count<maxRows && rs.Read(); count++) {
         for (int i=0; i<cols; i++) {
            keys[i] = GetKeyFromResultSet(i, persisters[i],
               (i==cols-1) ? optionalID : null, rs, session );
         }

         // 取得结果行集并进行处理。
         object[] row = GetRow(rs, persisters, s