NHibernate采用参数名后绑定方式。
根据实体属性映射信息生成相关操作的SQL语句时,并不生成参数名,在SQL字符串层面用一个通配符?表示参数名,在对象层面用SqlCommand目录下的Parameter类表示一个参数。这样有利于中间对SQL语句的的分析和再处理。在SQL语句快要执行之前,NH才生成具体的参数名,填入到SQL 语句之中,并把对应的参数名、参数值赋值到DbParameter对象上。
为了支持这种处理,相关的几个最基础的类便是SqlCommand目录下的SqlString、SqlStringBuilder、ISqlStringVisitor。
1. SqlString
代表一个SQL语句字符串。它内部将一个完整的SQL语句切分成一个个独立的部分(parts)进行管理,目的就是支持参数名后绑定。例如SQL语句 SELECT * FROM TableA WHERE Col1=? AND Col2='asdf? asdf' AND Col3=?,在SqlString内部表示为下面四个部分(parts):
SELECT * FROM TableA WHERE Col1=
{?}
AND Col2='asdf? asdf' AND Col3=
{?}
每一行表示一个part。part分为两种类型:System.String和NHibernate.SqlCommand.Parameter,上面{?}表示是一个Parameter对象。
用下面的代码创建一个SqlString对象,调试进去可以查看到上面的结果。
SqlString sqlstring = SqlString.Parse("SELECT * FROM TableA WHERE Col1=? AND Col2='asdf? asdf' AND Col3=?");
在NH内部,SqlString只是一个数据格式的承载者,不能通过这个类直接去操作各个part,要创建、重新编辑SqlString对象,使用SqlStringBuilder,要遍历访问各个part,通过ISqlStringVisitor。
创建SqlString时需要注意:a. SQL语句中不能包含注释 b. 参数以单个?表示 c. 单引里面的字符串值如果包含单引号,应当写成两个单引号才不会有问题。
2. SqlStringBuilder
用一个完整的SQL语句创建SqlString对象,可以直接使用SqlString.Parse(string)方法;如果基于多个parts拼装一个 SqlString对象,或者是对已有的SqlString对象重新编辑/拼装,使用SqlStringBuilder。
SqlStringBuilder的使用者还是得了解SqlString对象的工作模式,严格的按照各个part的顺序使用相应的方法逐个添加。
对于添加String或者Parameter类型的part,处理很简单;添加一个SqlString,在处理上复杂点,使用一个内嵌类AddingSqlStringVisitor。
3. ISqlStringVisitor
通过Visitor模式、SqlStringBuilder类,SqlString类本身的职责变得很单纯:以自己的数据结构表示一个SQL语句,为 ISqlStringVisitor实现者提供访问自己的方法。SqlString对象的Visit方法中按照顺序遍历各个part,把part传给 ISqlStringVisitor相关方法。
ISqlStringVisitor的实现者AddingSqlStringVisitor将各个part添加到拥有者SqlStringBuilder 中,从而实现在SqlStringBuilder中把SqlString的各个part添加进来。而访问者SqlStringFormatter的主要目的是将SqlString中的Parameter对象生成参数名,从而得到最终可执行的SQL语句。
4. 参数名后绑定
根据各种映射信息来构造SQL语句时,统一的使用一个?或者Parameter对象,有利于构造、编辑处理中对参数的识别。使用这种方式处理,就只能按照约定的命名规则来生成参数、操作参数,从DriverBase的ToParameterName(int index)方法可以看到,就是用前缀p+参数位置索引来生成参数名。
参数名后绑定的实现,查看DriverBase的SetCommandText方法。