nhibernate源码分析之六: Criteria数据加载
ICriteria是使用Expression进行数据加载的接口, 提供了设置表达式(Expression), 排序方式(Order), 分页记录等操作.
它使用一种类似于SQL语句where表达表的方式来加载满足条件的数据.
下面以一个查询Username为billy, Password为test的用户为例来分析nh中Criteria数据加载是怎样工作的.
查询代码如下:
Expression.Eq("Password", "test") );
IList users = session.CreateCriteria( typeof(Username) ).Add( ex ).List();
这里先建立了一个Expression, 然后加入到ICriteria中. ICriteria通过session.CreateCriteria( type )获得.
注意: ICriteria的实现类CriteriaImpl是一个Internal类, 因此不能在nh程序集外直接创建.
SqlString和SqlStringBuilder对象
因后面的代码多次用到SqlString和SqlStringBuilder对象,这里先说明一下。
SqlString对象用于存储伪Sql语句中的各个部分,注意,是伪Sql语句哦~, 不是实际的sql语句,不过实际的sql语句是通过SqlString对象解析而来的。
假如我有这样的一个伪sql语句,
select * from User u
where u.Username = @Username and u.Password = @Password
那么由此产生的SqlString将包含一个这样的数组,{"select", "*", "from", "User", "where", "Username", "=", param, "and", "Password", "=", param2 }, 其中param, param2是nh中的Paramenter(参数)对象.
SqlStringBuilder对象专门用于创建SqlString对象,因为SqlString是不能修改它内部的sqlPart的,如要修改sqlPart, 必须使用SqlStringBuilder.
Expression对象
Expression是所有表达式对象的祖先, 它使用Factory Method(工厂模式)来创建具体的表达式(如相等表达式EqExpression).
这里介绍几个最要的表达式对象:
SimpleExpression: 简单表达式对象, 是所有简单操作表达式的父类, 如EqExpression, GtExpression等;
LogicalExpression: 逻辑表达式对象, 用于指定两个表达式的逻辑关系, 有AndExpression和OrExpression两个子类;
最值的关注就是Expression如何产生它的sqlString了, 这个由ToSqlString方法完成.
// *** SimpleExpression.cs 60行***
public override SqlString ToSqlString(ISessionFactoryImplementor factory,
System.Type persistentClass, string alias) {
SqlStringBuilder sqlBuilder = new SqlStringBuilder();
IType propertyType = ((IQueryable)factory.GetPersister(persistentClass)).GetPropertyType(propertyName);
string[] columnNames = GetColumns(factory, persistentClass, propertyName, alias);
string[] paramColumnNames = GetColumns(factory, persistentClass, propertyName , null);
Parameter[] parameters = Parameter.GenerateParameters(factory, alias, paramColumnNames, propertyType);
for(int i = 0; i < columnNames.Length; i++) {
if(i > 0) sqlBuilder.Add(" AND ");
sqlBuilder.Add(columnNames[i])
.Add(Op)
.Add(parameters[i]);
}
return sqlBuilder.ToSqlString();
}
取得属性对应的数据列名, 并创建Parameter对象, 在解析SqlString时将根据Parameter产生实际的IDbParameter对象.
// *** SimpleExpression.cs 65行***
public override SqlString ToSqlString(ISessionFactoryImplementor factory,
System.Type persistentClass, string alias) {
SqlStringBuilder sqlBuilder = new SqlStringBuilder();
SqlString lhSqlString = lhs.ToSqlString(factory, persistentClass, alias);
SqlString rhSqlString = rhs.ToSqlString(factory, persistentClass, alias);
sqlBuilder.Add(new SqlString[] {lhSqlString, rhSqlString},
"(", Op, ")");
return sqlBuilder.ToSqlString();
}
先得到逻辑操作两边的表达式SqlString, 然后连同逻辑操作一起加入到sqlBuilder对象中。
另外一个要关注的就是GetTypedValues方法了,它返回表达式中属性的类型和值,用于给参数赋值。
加载过程源码分析
public ICriteria CreateCriteria(System.Type persistentClass) {
return new CriteriaImpl(persistentClass, this);
}
创建一个CriteriaImpl, 并将对象类型和会话传递给去.
public ICriteria Add(NExpression.Expression expression) {
expressions.Add(expression);
conjunction.Add(expression);
return this;
}
将表达式加入到集合中.
//*** CriteriaImpl.cs 67行 ***
public IList List() {
return session.Find(this);
}
调用session.Find, 看来CriteriaImpl没干实事,只是存储一些查询信息.
//*** CriteriaImpl.cs 3748行 ***
public IList Find(CriteriaImpl criteria) {
System.Type persistentClass = criteria.PersistentClass;
ILoadable persister = (ILoadable) GetPersister(persistentClass);
CriteriaLoader loader = new CriteriaLoader(persister, factory, criteria);
// 省略若干行...
try {
return loader.List(this);
}
catch (Exception e) {
throw new ADOException("problem in find", e);
}
// 省略若干行...
}
先取得要查询对象的持久化类, 然后创建一个CriteriaLoader, 最后返回CriteriaLoader.List的结果.
CriteriaLoader是数据加载类Loader族中的一员, 用于实现Criteria数据加载.
//*** CriteriaLoader.cs 28行 ***
public CriteriaLoader(ILoadable persister, ISessionFactoryImplementor factory,
ICriteria criteria) : base(persister, factory) {
this.criteria = criteria;
// 此句无用, 不知为何保留?
IEnumerator iter = criteria.IterateExpressions();
StringBuilder orderByBuilder = new StringBuilder(60);
bool commaNeeded = false;
iter = criteria.IterateOrderings();
while ( iter.MoveNext() ) {
Order ord = (Order) iter.Current;
if(commaNeeded) orderByBuilder.Append(StringHelper.CommaSpace);
commaNeeded = true;
orderByBuilder.Append(ord.ToStringForSql(factory, criteria.PersistentClass, alias));
}
RenderStatement(criteria.Expression.ToSqlString(factory, criteria.PersistentClass, alias),
orderByBuilder.ToString(), factory);
PostInstantiate();
}
首先枚举排序对象, 并组合成orderby子句(ToStringForSql比较简单, 请参考Order对象);
然后调用父类AbstractEntityLoad的RenderStatement方法生成SqlString对象;
最后调用父类Loader的PostInstantiate方法.
//*** AbstractEntityLoader.cs 72行 ***
protected void RenderStatement(SqlString condition, string orderBy,
ISessionFactoryImplementor factory) {
SqlSelectBuilder sqlBuilder = new SqlSelectBuilder(factory);
sqlBuilder.SetFromClause(
persister.FromTableFragment(alias).Append(
persister.FromJoinFragment(alias, true, true)
)
);
sqlBuilder.AddWhereClause(condition);
sqlBuilder.SetOrderByClause(orderBy);
this.sqlString = sqlBuilder.ToSqlString();
int joins=0; // I added.
classPersisters = new ILoadable[joins+1];
classPersisters[joins] = persister;
}
创建一个SqlSelectBuilder对象, 这是一个用于建立select语句的对象, 然后加入form子句、where子句和排序字符串。
注:代码中省略了OuterJoin的处理代码, 关于OuterJoin数据加载, 将在后续文章中单独分析.
//*** SqlSelectBuilder.cs 167行 ***
public SqlString ToSqlString() {
SqlStringBuilder sqlBuilder = new SqlStringBuilder();
sqlBuilder.Add("SELECT ")
.Add(selectClause)
.Add(" FROM ")
.Add(fromClause)
.Add(outerJoinsAfterFrom);
sqlBuilder.Add(" WHERE ");
if(whereSqlStrings.Count > 1) {
sqlBuilder.Add((SqlString[])((ArrayList)whereSqlStrings).ToArray(typeof(SqlString)),
null, "AND", null, false);
}
else {
sqlBuilder.Add((SqlString)whereSqlStrings[0], null, null, null, false);
}
sqlBuilder.Add(outerJoinsAfterWhere);
if (orderByClause != null && orderByClause.Trim().Length > 0) {
sqlBuilder.Add(" ORDER BY ")
.Add(orderByClause);
}
return sqlBuilder.ToSqlString();
}
创建一个SqlStringBuilder对象并将SQL关键字和给定的查询信息组装成一个SqlString对象。
//*** CriteriaLoader.cs 55行 ***
public IList List(ISessionImplementor session) {
ArrayList values = new ArrayList();
ArrayList types = new ArrayList();
IEnumerator iter = criteria.IterateExpressions();
while ( iter.MoveNext() ) {
Expression.Expression expr = (Expression.Expression) iter.Current;
TypedValue[] tv = expr.GetTypedValues( session.Factory, criteria.PersistentClass );
for ( int i=0; i<tv.Length; i++ ) {
values.Add( tv[i].Value );
types.Add( tv[i].Type );
}
}
object[] valueArray = values.ToArray();
IType[] typeArray = (IType[]) types.ToArray(typeof(IType));
return Find(session, valueArray, typeArray, true, criteria.Selection, null, null);
}
先枚举表达式对象,取得所有表达式中参数的值和类型,然后调用Loader.Find方法。
Loader对象的Find方法是所有数据加载的最终方法,将在后续的文章中单独分析。
转载于:https://www.cnblogs.com/peixiaohua1983/archive/2009/03/18/1415452.html
nhibernate源码分析之六: Criteria数据加载相关推荐
- Spring Ioc源码分析 之 Bean的加载(6):属性填充(populateBean())
"属性填充",也是在populateBean()方法中. 首先回顾下CreateBean的主流程: 如果是单例模式,从factoryBeanInstanceCache 缓存中获取B ...
- Myabtis源码分析五-Mybatis配置加载完全图解,建造者模式的使用,涵盖Java各种技术栈
private SqlSessionFactory sqlSessionFactory; @Before public void init() throws IOException { //----- ...
- Spring Ioc源码分析 之 Bean的加载(4):实例化Bean(createBeanInstance()方法)
实例化 Bean 在doCreateBean()代码 <2> 处,有一行代码instanceWrapper = createBeanInstance(beanName, mbd, args ...
- Spring Ioc源码分析 之 Bean的加载(7):初始化
接着分析doCreateBean()的第6步--初始化 bean 实例对象 首先回顾下CreateBean的主流程: 如果是单例模式,从factoryBeanInstanceCache 缓存中获取Be ...
- Spring Ioc源码分析 之 Bean的加载(5):循环依赖处理(populateBean())
首先回顾下Bean加载的主流程: 1.如果是单例模式,从factoryBeanInstanceCache 缓存中获取BeanWrapper 实例对象并删除缓存 2.调用 createBeanInsta ...
- MPF源码分析之资源文件加载
本文将分析MPF客户端框架中资源文件相关的源代码,以github包中提供的qq界面demo作为 起点,一步一步分析程序的运行原理: 主程序很简单,代码如下: int APIENTRY _tWinMai ...
- 直播app系统源码通过CSS液体实现加载动画
直播app系统源码通过CSS液体实现加载动画 首先我们要让元素能够旋转起来,可以使用transform中的rotate进行2D的360deg旋转. 紧接着我们可以通过CSS变量(–开头的形式)结合an ...
- 框架源码专题:springIOC的加载过程,bean的生命周期,结合spring源码分析
文章目录 1.BeanFactory和ApplicationContext的区别? 2. IOC与 Bean的加载过程 ①:初始化容器DefaultListableBeanFactory ②:创建读取 ...
- 云客Drupal源码分析之类型化数据Typed Data API
各位<云客drupal源码分析>系列的读者: 本系列一直以每周一篇的速度进行博客原创更新,希望帮助大家理解drupal底层原理,并缩短学习时间,但自<插件系统(上)>主题开始博 ...
最新文章
- hadoop namenode启动不了_Hadoop框架:HDFS高可用环境配置
- 【项目管理】虚拟团队
- hdu 4196(数论)
- 容器技术Docker K8s 8 容器服务ACK Pro版集群
- 《计算机组成原理阅读笔记》
- 解决win10系统安装ch341驱动程序显示“预安装成功”的一个方法
- C4D R26 安装教程
- C++控制台五子棋(带背景音乐)
- 时序分析——Latch timing
- 爬取街拍图片_如何拍摄好街拍照片
- JAVAEE和项目开发——JSP详解
- 广西国家级自然保护区功能区划图(展示)
- 地球动力学类毕业论文文献都有哪些?
- android自适应屏幕翻转,Android中正确自适应屏幕翻转
- DOM实现元素拖拽,滚轮事件和特效动画缓冲运动处理
- CVE-2017-8464(震网三代)漏洞分析与复现
- 8月第4周国内新闻类网站/频道:QQ新闻居首
- 链路聚合的手工与LACP配置
- 热电阻和热电偶的区别
- VM虚拟机只有IPv6,没有ipv4
热门文章
- layUI table 按条件搜索 结果整个页面刷新
- 第十八届浙大城市学院程序设计竞赛(同步赛)签到题ABDFGJL
- 【LOJ101】最大流(Edmonds-Karp)
- 【NOIP2009】【Vijos1752】潜伏者
- java opencv 阀值分割_利用OpenCV实现局部动态阈值分割
- SpringCloud→分布式解决方案、包含主要工具、启动流程、web发展阶段、实现配置中心
- linux系统给串口权限,让ubuntu串口和USB设备不用root权限访问
- 计算机网络—SR选择重传协议
- 操作系统—进程同步与互斥问题之生产者消费者问题,附赠PV操作题解题思路(思维导图版)
- 计算机网络—停止等待协议(思维导图)