转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 数据库 >> Sql Server >> 正文
nhibernate源码分析之四 持久化操作与SQL语句         

nhibernate源码分析之四 持久化操作与SQL语句

作者:闵涛 文章来源:闵涛的学习笔记 点击数:2200 更新时间:2007/11/14 11:13:17


持久化操作由与持久对象关联的持久化类来完成,持久化类是实现IClassPersister接口的类,每个持久对象都有一个关联的持久化类,这些持久化类存储在会话工厂的classPersisters集合中,nhibernate允许用户通过自定义的持久化类来持久化数据。

IClassPersister接口定义了基本的CRUD操作,在nhibernate中由AbstractEntityPersister类实现,这是一个抽象类,有两个具体的派生类,分别是:EntityPersister和normalizedEntityPersister,前者用于一个表一个类的情况,后面用于一个表一个子类的情况。

在分析持久化操作之前先来介绍几个辅助类:

1. SqlString: 用于构造IDbCommand对象;
2. SqlStringBuilder: 用于构造SqlString对象;
3. SqlInsertBuilder: 用于构造Insert操作的SqlString对象;
4. SqlUpdateBuilder: 用于构造Update操作的SqlString对象;
5. SqlDeleteBuilder: 用于构造Delete操作的SqlString对象;
6. Parameter: 用于转换到实现IDbParameter接口对象;
7. IPrepare: 用于准备和存储IDbCommand接口,由PrepareImpl实现。

下面以一个有identity符识的对象为例说明其持久化的流程。

一. Insert

因为持久对象有identity标识符,所以执行Save操作时,是立即调用持久对象的持久化类来执行Insert操作,而不是加入到计划集合中(原因请参考 nhibernate源码分析之三)。但最终的处理方式是一致的。

//*** EntityPersister.cs ***

public override void Insert(object[] fields, object obj, ISessionImplementor session) {
   if(UseDynamicInsert) {
      bool[] notNull = GetNotNullInsertableColumns(fields);
      Insert(fields, notNull, GenerateInsertString(false, notNull), obj, session);
   }
   else {
      Insert(fields, PropertyInsertability, SqlInsertString, obj, session);
   }
}Insert方法首先检查是否使用dynamic-insert(动态插入),如使用则只插入非空的字段,dynamic-insert可在映射文件中指定;然后通过GenerateInsertString方法取得insert操作的SqlString。

protected virtual SqlString GenerateInsertString(bool identityInsert, bool[] includeProperty) {
   SqlInsertBuilder builder = new SqlInsertBuilder(factory);
   builder.SetTableName(TableName);

   for(int i = 0 ; i < hydrateSpan; i++) {
      if(includeProperty[i]) builder.AddColumn(propertyColumnNames[i], PropertyTypes[i]);
   }    

   if (IsPolymorphic) builder.AddColumn(DiscriminatorColumnName, DiscriminatorSQLString);

   if(identityInsert==false) {
      builder.AddColumn(IdentifierColumnNames, IdentifierType);
   }
   else {
      if(dialect.IdentityInsertString!=null) {
         builder.AddColumn(IdentifierColumnNames[0], dialect.IdentityInsertString);
      }
   }

   return builder.ToSqlString();
}首先构造一个SqlInsertBuilder对象,然后加入所有要插入的字段,hydrateSpan在AbstractEntityPersister类中定义,是持久对象的属性Count;然后判断持久对象是否为Polymorphic(通过字段值实现多态),如是则加入辨别列,辨别值可通过映射文件中的discriminator-value来指定;接着判断是否要加入标识列,最后返回一个SqlString对象。注意:在ToSqlString方法中,可以看到我们熟悉的INSERT INTO语句。

SqlInsertBuilder类的AddColumn方法有多个重载,这里只列出比较重要的一个(加入参数列)。

//*** SqlInsertBuilder.cs ***
  
public SqlInsertBuilder AddColumn(string[] columnNames, IType propertyType) {
   Parameter[] parameters = Parameter.GenerateParameters(factory, columnNames, propertyType);

   for(int i = 0; i < columnNames.Length; i++) {
      this.columnNames.Add(columnNames[i]);
      columnValues.Add(parameters[i]);
   }
   
   return this;
}通过Parameter的静态方法GenerateParameters创建Parameter,然后加入到集合中。

//*** EntityPersister.cs ***

public object Insert(object[] fields, bool[] notNull, SqlString sql,
      object obj, ISessionImplementor session) {

   IDbCommand statement = null;
   IDbCommand idSelect = null;

   if(dialect.SupportsIdentitySelectInInsert) {
      statement = session.Preparer.PrepareCommand( dialect.AddIdentitySelectToInsert(sql) );
      idSelect = statement;
   }
   else {
      statement = session.Preparer.PrepareCommand(sql);
      idSelect = session.Preparer.PrepareCommand(SqlIdentitySelect);
   }

   try {
      Dehydrate(null, fields, PropertyInsertability, statement, session);
   }
   catch (Exception e) {
      throw new HibernateException("...", e);
   } 

   try {
      if(dialect.SupportsIdentitySelectInInsert==false) {
         statement.ExecuteNonQuery();
      }

      IDataReader rs = idSelect.ExecuteReader();
      object id;
      try {
         if ( !rs.Read() ) throw new HibernateException("...");
         id = IdentifierGeneratorFactory.Get( rs, IdentifierType.ReturnedClass );
      }
      finally {
         rs.Close();
      }

      return id;
   }
   catch (Exception e)  {
      throw e;
   }
}首先声明两个IDbCommand对象,statement用于insert,idSelect用于检查标识符,然后通过IPreparer接口来准备IDbCommand对象, 如dialect(数据库方言)支持在Insert语句中后检索标识符,则将insert与检查标识符操作合并;然后调用Dehydrate对参数进行赋值;最后执行IDbCommand并返回id。

IPreparer用于准备IDbCommand对象,并将当前会话中已执行过的IDbCommand对象存储在hashtable表中,这样对于批量操作时可以提高性能,而IDbCommand对象则由SqlString对象创建。

//*** SqlString.cs ***

public IDbCommand BuildCommand(IDriver driver) {
   int paramIndex = 0;
   IDbCommand cmd = driver.CreateCommand();

   StringBuilder builder = new StringBuilder(sqlParts.Length * 15);
   for(int i = 0; i < sqlParts.Length; i++) {
      object part = sqlParts[i];
      Parameter parameter = part as Parameter;
    
      if(parameter!=null) {
         string paramName = "p" + paramIndex;
         builder.Append( parameter.GetSqlName(driver, paramName) );
         IDbDataParameter dbParam = parameter.GetIDbDataParameter(cmd, driver, paramName);
         cmd.Parameters.Add(dbParam);
     
         paramIndex++;
      }
      else {
         builder.Append((string)part);
      }
   }

   cmd.CommandText = builder.ToString();
   return cmd;
}

通过Driver创建IDbCommand对象,如果part(组成Sql语句的一部分)为Parameter,则创建IDbDataParameter并加入到IDbCommand中。所有的part就组成Sql语句。
//*** EncityPersister ***

protected virtual int Dehydrate(object id, object[] fields, bool[] includeProperty,
      IDbCommand st, ISessionImplementor session) {
   int index = 1;

   index = 0;
 
   for (int j=0; j      if ( includeProperty[j] ) {
         PropertyTypes[j].NullSafeSet( st, fields[j], index, session );
         index += propertyColumnSpans[j

[1] [2]  下一页


[Access]sql随机抽取记录  [Access]ASP&SQL让select查询结果随机排序的实现方法
[系统软件]SQL语句性能优化--LECCO SQL Expert  [C语言系列]SQL Server到DB2连接服务器的实现
[C语言系列]SQL Server到SYBASE连接服务器的实现  [C语言系列]SQL Server到SQLBASE连接服务器的实现
[C语言系列]SQL Server连接VFP数据库的实现  [C语言系列]ASP+SQL Server之图象数据处理
[C语言系列]SQL Server连接ACCESS数据库的实现  [C语言系列]DBA的最佳选择—图形界面还是T-SQL命令?
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · Sql Server  · MySql
    · Access  · ORACLE
    · SyBase  · 其他
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台