nhibernate: HQL数据加载

NH中,HQL是一个十分强大的面向对象的查询语言,简单的说,就是不需要使用实际的表名和列名来查询数据,而改用类名和属性。 有两种方式来执行HQL数据加载,一种是直接使用ISession的Find方法,另一种是使用IQuery接口。 IQuery接口提供了一些额外的设置,最重要的就是分页了,这个和ICriteria差不多,另外一些就是设置参数的值了。 IQuery最终还是会调用ISession的Find方法,下面来分析一下IQuery中HQL语句的处理. 示例代码: IQuery query = session.CreateQuery( " from User u where u.Name = :Name " ) query.SetString( "Name", "billy" ); IList users = query.List(); 源码分析: //*** SessionImpl.cs 1760行 ***/ public IQuery CreateQuery(string queryString) {    return new QueryImpl(queryString, this); } 创建一个QueryImpl对象,并传递HQL查询文本和会话. 注意: IQuery的实现类QueryImpl是一个Internal类, 因此不能在nh程序集外直接创建. //*** QueryImpl.cs 70行 **/ public IQuery SetParameter(int position, object val, IType type) {    int size = values.Count;    if ( position<size ) {       values[position] = val;       types[position] = type;    }    else {       for (int i=0; i<position-size; i++) {          values.Add(null);          types.Add(null);       }       values.Add(val);       types.Add(type);    }    return this; } public IQuery SetParameter(string name, object val, IType type) {    namedParameters[name] = new TypedValue(type, val);    return this; } 在IQuery中,参数有两种情况,一种是命名参数,一种是未命名参数, 上面给出的示例代码是使用命名参数。 SetString方法直接调用SetParameter方法来设置命名参数,SetParameter参数有多个重载的版本,用于适应不同的IType, 如果要设置未命名参数,那么应通过参数的位置来设置。 TypedValue用对象来于保存参数的类型和值。 //*** QueryImpl.cs 47行 ***/ public virtual IList List() {    IDictionary namedParams = new Hashtable( namedParameters );    string query = BindParameterLists(namedParams);    return session.Find(query, (object[]) values.ToArray(typeof(object)),       (IType[])types.ToArray(typeof(IType)),    selection, namedParams, lockModes); } 在执行查找之前,必须先处理所有的集合参数,像in关健字就用到了集合参数。 //*** QueryImpl.cs 280行 *** protected string BindParameterLists(IDictionary namedParams) {    string query = queryString;    foreach( DictionaryEntry de in namedParametersLists ) {       query = BindParameterList( query, (string) de.Key, (TypedValue) de.Value, namedParams );    }    return query; } 所有集合参数都存储在namedParametersLists集合中(可参见SetParameterList方法),这里通过枚举对各个集合参数进行绑定。 //*** QueryImpl.cs 288行 *** private string BindParameterList(string queryString, string name,    TypedValue typedList, IDictionary namedParams) {    ICollection vals = (ICollection) typedList.Value;    IType type = typedList.Type;    StringBuilder list = new StringBuilder(16);    int i=0;    foreach( object obj in vals ) {       string alias = name + i++ + StringHelper.Underscore;       namedParams.Add( alias, new TypedValue( type, obj ) );       list.Append( ':' + alias );       if ( i < vals.Count ) list.Append( StringHelper.CommaSpace );    }    return StringHelper.Replace( queryString, ':' + name, list.ToString() ); } BindParameterList方法遍历值集合,然后将它们加入到命名参数集合(namedParams)中,最后修改HQL查询文本。 例如:在HQL中是" ... name in ( :Name )", 如果值集合有三个值,那么修改后的HQL是 "... name in ( :Name0_, :Name1_, :Name2_ ) "; //*** SessionImpl.cs 1571行 *** public IList Find(string query, object[] values, IType[] types,    RowSelection selection,IDictionary namedParams, IDictionary lockModes) {    QueryTranslator[] q = GetQueries(query, false);    IList results = new ArrayList();    dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called    //execute the queries and return all result lists as a single list    try {       for (int i=0; i<q.Length; i++ ) {          IList currentResults;          try {             currentResults = q[i].FindList(this, values, types, true, selection, namedParams, lockModes);          }          catch (Exception e) {             throw new ADOException("Could not execute query", e);          }          for (int j=0;j<results.Count;j++) {             currentResults.Add( results[j] );          }          results = currentResults;       }    }    finally {       dontFlushFromFind--;    }    return results; } 根据HQL查询文本生成QueryTranslator对象,然后调用QueryTranslator的FindList方法返回查询结果。 //*** QueryTranslator.cs 1051行 *** public IList FindList( ISessionImplementor session, object[] values, IType[] types,    bool returnProxies, RowSelection selection, IDictionary namedParams, IDictionary lockModes) {    return base.Find(session, values, types, returnProxies, selection, namedParams, lockModes); } FindList直接调用父类Loader的Find方法来查询数据,所有的数据加载(当然包括Criteria加载)最终都由Loader进行处理,关于这个类,将在后续的文章中单独进行分析。 //*** SessionImpl.cs 1616行*** private QueryTranslator[] GetQueries(string query, bool scalar) {    // a query that naemes an interface or unmapped class in the from clause    // is actually executed as multiple queries    string[] concreteQueries = QueryTranslator.ConcreteQueries(query, factory);

 

   // take the union of the query spaces (ie the queried tables)    QueryTranslator[] q = new QueryTranslator[concreteQueries.Length];    ArrayList qs = new ArrayList();    for (int i=0; i<concreteQueries.Length; i++ ) {       q[i] = scalar ? factory.GetShallowQuery( concreteQueries[i] )                     : factory.GetQuery( concreteQueries[i] );       qs.AddRange( q[i].QuerySpaces );    }    return q; } 分析HQL查询文本,如果是由多个SQL语句组成,就要将其进行分割,最后由会话工厂根据HQL文本创建QueryTranslator对象。 //*** SessionFactoryImpl.cs 429行 *** private QueryTranslator GetQuery(string query, bool shallow) {    QueryCacheKey cacheKey = new QueryCacheKey(query, shallow);    QueryTranslator q = (QueryTranslator) Get(cacheKey);    if ( q==null) {       q = new QueryTranslator(dialect);       Put(cacheKey, q);    }    q.Compile(this, query, querySubstitutions, shallow);    return q; } 检查在缓存中是否已存在相同的QueryTranslator对象,如没有,则创建一个并将其放入缓存, 然后调用QueryTranslator的Compile方法对HQL查询文本进行解析, 有关解析SQL的细节,请参考解析HQL语句

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值