Richie

Sometimes at night when I look up at the stars, and see the whole sky just laid out there, don't you think I ain't remembering it all. I still got dreams like anybody else, and ever so often, I am thinking about how things might of been. And then, all of a sudden, I'm forty, fifty, sixty years old, you know?

NHibernate代码解析 - SqlCommand - SqlBuilder Template StringTokenizer

    SqlBuilder几个类用于构造SELECT、INSERT、DELETE、UPDATE的SQL语句,类图如下
    
    1. SqlBaseBuilder
    主要提供对WHERE子句生成的支持。NH可能对简单的属性生成col1=?这样的WHERE条件,也可能对CollectionType的属性生成 col1=? AND col2=?这样的组合条件(无需使用者自己一个个column循环处理,而是把CollectionType对应的columns和属性的IType传入,由SqlBaseBuilder来处理)。这些WHERE条件子句的生成处理都封装在SqlBaseBuilder中。
    2. INSERT语句里面没有WHERE子句,所以SqlInsertBuilder不从SqlBaseBuilder继承。 SqlUpdateBuilder、SqlDeleteBuilder等其它几个都会有WHERE子句所以都从SqlBaseBuilder继承下来。
    NH的原则是中间处理过程中的SQL语句基本都以SqlString对象表示,只在执行之前才由SqlString生成SQL语句,因此这几个 SqlBuilder类的产出就是一个SQL语法上完整的SqlString对象,因此都实现了ISqlStringBuilder接口。 WhereBuilder只是方便其它地方需要构造WHERE条件子句之用(SqlBaseBuilder是abstract类),它的产出并非一个完整的SQL语句,因此没有实现ISqlStringBuilder接口,通过WhereClause方法返回WHERE条件子句的SqlString。
    3. SqlSelectBuilder、SqlSimpleSelectBuilder的区别
    SqlSelectBuilder用于构造一个稍复杂的SQL语句,可能包含JOIN子句、子查询等;而SqlSimpleSelectBuilder只是用于构造简单的SQL。为什么要这样,觉得没什么必要,是NH升级扩展的产物还是作者的随意?

    SqlUpdateBuilder测试代码
{
    Configuration cfg 
= new Configuration();
    ISessionFactory factory 
= cfg.BuildSessionFactory();
    ISessionFactoryImplementor factoryImpl 
= (ISessionFactoryImplementor)factory;

    SqlUpdateBuilder update 
= new SqlUpdateBuilder(factoryImpl);
    update.SetTableName(
"ItemTable");
    
//test AddColumn( string columnName, object val, ILiteralType literalType )
    update.AddColumn("TestCol""my test", (NHibernate.Type.ILiteralType)NHibernateUtil.AnsiString);

    
//test AddColumns( string[] columnNames, bool[] updateable, IType propertyType )
    update.AddColumns(new string[] { "Col0" }, null, NHibernateUtil.AnsiString);
    update.AddColumns(
new string[] { "Col1" }, null, NHibernateUtil.Int32);

    
//test SetIdentityColumn( string[ ] columnNames, IType identityType )
    update.SetIdentityColumn(new string[] { "UserID" }, NHibernateUtil.Guid);

    
//test AddWhereFragment( string[ ] columnNames, IType type, string op )
    update.AddWhereFragment(new string[] { "CreateTime" } , NHibernateUtil.DateTime, ">");

    
//test ToSqlString()
    
//string sql = update.ToSqlString().ToString();
    SqlString sqlstring = update.ToSqlString();

    SqlStringFormatter formater 
= new SqlStringFormatter((ISqlParameterFormatter)(factoryImpl.ConnectionProvider.Driver));
    sqlstring.Visit(formater);
    
string sql = formater.GetFormattedText();

    
string sqlExpected = "UPDATE ItemTable SET TestCol = 'my test', Col0 = @p0, Col1 = @p1 WHERE UserID = @p2 AND CreateTime>@p3";
    Assert.AreEqual(sqlExpected, sql, 
"SQL String");
}
    SqlSelectBuilder测试代码
{
    Configuration cfg 
= new Configuration();
    ISessionFactory factory 
= cfg.BuildSessionFactory();

    ISessionFactoryImplementor factoryImpl 
= (ISessionFactoryImplementor)factory;
    SqlSelectBuilder select 
= new SqlSelectBuilder(factoryImpl);

    select.SetSelectClause(
"pi.PlantCode, pi.ItemCode, pi.SafeStock");
    select.SetFromClause(
"PlantItem""pi");
    select.SetOuterJoins(
        
new SqlString(" INNER JOIN Plant p ON p.PlantCode=pi.PlantCode LEFT OUTER JOIN Item i ON i.ItemCode=pi.ItemCode "),
        
new SqlString(" i.ItemType='A' "));
    select.SetOrderByClause(
"pi.PlantCode ASC, pi.ItemCode DESC");
    select.SetGroupByClause(
"pi.PlantCode, pi.ItemCode");
    select.SetWhereClause(
"pi"new string[] { "Status" }, NHibernateUtil.YesNo);

    
string sql = select.ToSqlString().ToString();
    
string expected = "SELECT pi.PlantCode, pi.ItemCode, pi.SafeStock FROM PlantItem pi INNER JOIN Plant p ON p.PlantCode=pi.PlantCode LEFT OUTER JOIN Item i ON i.ItemCode=pi.ItemCode  WHERE i.ItemType='A' AND pi.Status = ? GROUP BY pi.PlantCode, pi.ItemCode ORDER BY pi.PlantCode ASC, pi.ItemCode DESC";
    Assert.AreEqual(sqlExpected, sql, 
"SQL String");
}

    4. Util\StringTokenizer
    作用类似string.Split()函数,进行了扩展改造,可以返回定界字符,实现了IEnumerable接口,以枚举的方式读取切分后的各个部分。因为在Template中有用到所以了解一下这个类。
    5. Template
    在SQL语句的列名前面添加字符串标签;把列名引用括号对``(注意不是两个单引号)替换成Dialect指定的列名引用开闭符号。
    例如:
{
    Dialect dialect 
= new MsSql2000Dialect();
    
string whereFragment = "col1='v`al`1' and `c_1` = 1";
    
string sql = Template.RenderWhereStringTemplate(whereFragment, dialect);
    
//sql : $PlaceHolder$.col1='v`al`1' and $PlaceHolder$.[c_1] = 1
    whereFragment = "select col1, col2 from itemtable as i where col1='v`al`1' and `c_1` = 1";
    sql 
= Template.RenderWhereStringTemplate(whereFragment, dialect);
    
//sql : select $PlaceHolder$.col1, $PlaceHolder$.col2 from itemtable as i where $PlaceHolder$.col1='v`al`1' and $PlaceHolder$.[c_1] = 1
}
    用途为,插入了字符串标签后,适当的位置可以将字符串标签进行替换,例如对表使用了别名等情况。

posted on 2007-01-23 23:00  riccc  阅读(1514)  评论(4编辑  收藏  举报

导航