Castle ActiveRecord学习实践(7):使用HQL查询

摘要:虽然ActiveRecord为我们提供了Find()FindAll()这样两个静态的查询方法,并且有Where特性可供使用,但是仍然不能解决实际开发中一些复杂的查询,这时我们就需要通过HQL查询来实现。

 

主要内容

1HQL概述

2SimpleQuery查询

3ScalarQuery查询

4.自定义查询

5.使用CallBack

 

一.HQL简单介绍

HQL全名是Hibernate Query Language,它是一种完全面向对象的查询语言。先来看一下HQL最基本的一些用法

1From子句

from Post

你也可以为Post起一个别名

from Post as post

或者省略as

from Post post

2Select 子句

select Name,Author from Blog

也可以使用elements函数来查询一个集合

select elements(blog.Posts) from Blog blog

3.使用聚合函数

HQL中也可以使用一些聚合函数

select count(*from Blog blog

 

select count(elements(blog.Posts)) from Blog blog

HQL支持的聚合函数有

avg(), sum(), min(), max(

count(*

count(), count(distinct ), count(all)

4Where子句

from Blog blog where blog.Name = ‘Terry Lee’

 

from Blog blog where blog.Name is not null

详细可以参考http://www.hibernate.org/hib_docs/reference/en/html/queryhql.html

 

二.SimpleQuery查询

SimpleQuery是一种最简单的查询,它直接处理HQL语句,并返回一个集合,没有复杂的参数处理。具体用法可以参考下例:

[ActiveRecord("Posts")]

public class Post : ActiveRecordBase

{

    
// 

    
/// <summary>

    
/// 查询某一类别的所有Posts

    
/// </summary>

    
/// <param name="_strCategory">类别名称</param>

    
/// <returns></returns>


    
public static Post[] GetPostsByCategory(string _strCategory)

    
{

        SimpleQuery query 
= new SimpleQuery(

            
typeof(Post),

            
@"from Post post where post.Category = ?",

            _strCategory

            );

 

        
return (Post[])ExecuteQuery(query);

    }


    

    
/// <summary>

    
/// 查询某一时间段内发表的所有Posts

    
/// </summary>

    
/// <param name="start">开始时间</param>

    
/// <param name="end">结束时间</param>

    
/// <returns></returns>


    
public static int[] GetPostsInterval(DateTime start,DateTime end)

    
{

        SimpleQuery query 
= new SimpleQuery(

            
typeof(Post),typeof(int),

            
@"select post.Id from Post post where post.Created between ? and ?",

            start,end

            );

 

        
return (int[])ExecuteQuery(query);

    }


}


看一下简单的测试代码:

[Test]

public void TestGetPostsByCategory()

{

    
string StrCategory = "Castle";

    

    IList list 
= (IList)Post.GetPostsByCategory(StrCategory);

 

    
int expectedCount = 2;

 

    Assert.IsNotNull(list);

    Assert.AreEqual(expectedCount,list.Count);

}


 

[Test]

public void TestGetPostsInterval()

{

    DateTime start 
= Convert.ToDateTime("2006-01-01");

    DateTime end 
= DateTime.Now;

 

    IList list 
= (IList)Post.GetPostsInterval(start,end);

 

    
int expectedCount = 2;

 

    Assert.IsNotNull(list);

    Assert.AreEqual(expectedCount,list.Count);

}

 

三.ScalarQuery查询

ScalarQuery查询也是一种简单的直接处理HQL的查询,它也没有复杂的参数处理,只不过返回的值不是集合而是单一的值,具体用法参考下例:

[ActiveRecord("Blogs")]

public class Blog : ActiveRecordBase

{

    
// 

    
/// <summary>

    
/// 查询某作者发表的所有Posts数量

    
/// </summary>

    
/// <param name="_StrAuthor">作者姓名</param>

    
/// <returns></returns>


    
public static int GetPostNumByAuthor(string _StrAuthor)

    
{

        ScalarQuery query 
= new ScalarQuery(

            
typeof(Blog),

            
@"select count(elements(blog.Posts)) from Blog blog where blog.Author = ?",

            _StrAuthor

            );

 

        
return (int)ExecuteQuery(query);

    }


}


看一下简单的测试代码

[Test]

public void TestGetPostNumByAuthor()

{

    
string _StrAuthor = "Terry Lee";

 

    
int result = Blog.GetPostNumByAuthor(_StrAuthor);

 

    
int expectedCount = 2;

 

    Assert.AreEqual(expectedCount,result);

}


四.自定义查询

在实际开发中,我们所面对的查询远不止上面所说得这么简单,有时候我们需要处理一些自定义的参数,或者执行自定义的查询语句,这时需要我们编写自定义的ActiveRecord查询,首先要添加一个类,让它继承于基类ActiveRecordBaseQuery,并覆写Execute()方法(或者实现IactiveRecordQuery接口),如下例所示

public class QueryWithNamedParameters : ActiveRecordBaseQuery

{

    
private string _authorName = null;

    
private int _maxResults = 2;

    

    
public QueryWithNamedParameters()

        : 
base(typeof(Blog)) 

    
{

 

    }


    

    
public string AuthorName

    
{

        
get return _authorName; }

        
set { _authorName = value; }

    }


    

    
public int MaxResults

    
{

        
get return _maxResults; }

        
set { _maxResults = value; }

    }


 

    
public override object Execute(ISession session)

    
{

        String hql 
= "from Blog blog";

 

        
if (_authorName != null)

            hql 
+= " where blog.Author = :author";

 

        IQuery q 
= session.CreateQuery(hql);

 

        
if (_authorName != null)

            q.SetString(
"author", _authorName);

 

        q.SetMaxResults(_maxResults);

 

        
return base.GetResultsArray(typeof(Blog), q.List(), nullfalse);

    }


}


使用我们自定义的类

/// <summary>

/// 自定义查询

/// </summary>

/// <param name="authorName"></param>

/// <returns></returns>


public static Blog[] GetThreeBlogsFromAuthor( string authorName )

{

    QueryWithNamedParameters q 
= new QueryWithNamedParameters();

    q.AuthorName 
= authorName;

    q.MaxResults 
= 3;

    
return (Blog[]) ExecuteQuery(q);

}


看一下简单的测试代码

[Test]

public void TestCustomQuery()

{

    
string _StrAuthor = "Terry Lee";

 

    IList list 
= Blog.GetThreeBlogsFromAuthor(_StrAuthor);

 

    
int expectedCount = 3;

 

    Assert.IsNotNull(list);

    Assert.AreEqual(expectedCount,list.Count);

}

 

五.使用CallBack

还有一种实现方式是使用Execute()方法,这种方式与我们前面所讲的自定义查询是差不多的,只不过不用增加额外的自定义类。

[ActiveRecord("Blogs")]

public class Blog : ActiveRecordBase

{

    
//

    
/// <summary>

    
/// 通过CallBack执行

    
/// </summary>

    
/// <param name="author"></param>

    
/// <returns></returns>


    
public static Blog[] GetPostsFromAuthor( string author )

    
{

        
return (Blog[]) Execute( typeof(Blog), new NHibernateDelegate(GetPostsFromAuthorCallback), author);

    }


 

    
private static object GetPostsFromAuthorCallback(ISession session, object instance )

    
{

        
// 创建查询

        IQuery query 
= session.CreateQuery( "from Blog blog where blog.Author = :author" );

 

        
// 设置参数

        query.SetString(
"author", (string) instance);

 

        
// 获取结果

        IList results 
= query.List();

 

        
// 转化结果为Array

        Blog[] blogs 
= new Blog[results.Count];

        results.CopyTo(blogs, 
0);

 

        
// 返回结果

        
return blogs;

    }


}

 

编写测试代码

[Test]

public void TestGetPostsFromAuthor()

{

    
string _StrAuthor = "Terry Lee";

 

    IList list 
= Blog.GetPostsFromAuthor(_StrAuthor);

 

    
int expectedCount = 4;

 

    Assert.IsNotNull(list);

    Assert.AreEqual(expectedCount,list.Count);

}

 

关于使用HQL查询就介绍到这儿了,相信通过HQL查询可以解决我们开发中的绝大多数的复杂查询问题。

 

 

参考资料

文中主要内容来自于Castle的官方网站http://www.castleproject.org

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2006-04-12 08:50 TerryLee 阅读(16058) 评论(23) 编辑 收藏

 回复 引用   
#1楼 2006-06-01 11:34 wujun[未注册用户]
Castle ActiveRecord的HQL查询语句,是先把要用到的查询的语句类型在类中定义好,然后再去调用相关的查询语句。在实际过程中,这种方式不够灵活。因为我们要用到某种查询语句,要先去定义它(做好查询模板),然后才能去赋变量调用它,不能用没有定义的语句。不知道我的理解是否正确。
 回复 引用 查看   
#2楼[楼主] 2006-06-01 11:51 TerryLee      
@wujun
呵呵,你说的这段话我不是很明白,“查询的语句类型在类中定义好”,什么是语句类型?

另外HQL也不是Castle AR的,它最早是在Hibernate中使用的,后来在NHibernate也是使用它,Castle AR既然在底层封装了NH,所以也只能使用它了。HQL是一个完全面向的查询语句,利用它我们可以解决AR中部分不能解决的复杂问题,怎么能说是不够灵活呢?

 回复 引用   
#3楼 2006-06-02 10:54 wujun[未注册用户]
我的意思是不是先把一些查询条件在类中先定义好,在调用时把SQL查询变量值传递给相关类中的查询语句.
 回复 引用 查看   
#4楼 2006-07-15 10:57 chaochao      
请问我查询POST后还需要显示出BLOG的名字,这种该怎么做呢,因为POST类中不包含BLOG中的字段信息
 回复 引用 查看   
#5楼[楼主] 2006-07-16 11:17 TerryLee      
@chaochao
Post类中不包含Blog中的字段信息?

[BelongsTo("post_blogid")]

public Blog Blog

{

get { return _blog; }

set { _blog = value; }

}

 回复 引用 查看   
#6楼 2006-07-17 10:40 chaochao      
谢谢TerryLee
如果我做联合查询,那么返回的数据就不会是一个实体,这个时候我如何把他绑定到一个实体,动态创建一个实体类吗?

 回复 引用   
#7楼 2006-08-15 00:49 ditto[未注册用户]
怎么做联合查询呢,麻烦TerryLee举个例子好吗?
比如:我想查询所有Post.Name like '%Castle%' 的相关 Blog集合的代码如何来写呢?

 回复 引用   
#8楼 2006-10-04 22:51 塞月[未注册用户]
数据库如果Category列是text格式的,而使用
SimpleQuery query = new SimpleQuery(

typeof(Post),

@"from Post post where post.Category = ?",

_strCategory

);


return (Post[])ExecuteQuery(query);

跑到最后一行就挂掉了。如果换成VARCHAR,马上就OK。
这是什么怪毛病啊。

 回复 引用   
#9楼 2006-10-04 22:54 塞月[未注册用户]
◎ditto

SimpleQuery query=new SimpleQuery(
typeof(Post),
@"from Post post where post.Contents like ?",
"%"+_content+"%");

return (Post[])ExecuteQuery(query);

这样写就可以了。不过注意我上面写的数据库的格式。Text就不成。

 回复 引用   
#10楼 2006-11-29 10:00 wang[未注册用户]
Hql语句怎么不能用Select呢,只有使用聚合函数才能用啊
万一出现这种"select '" + strName + "' as name 不知道怎么解决哦

 回复 引用 查看   
#12楼 2006-12-08 16:27 charleschen      
作上面的例子的时候
总是报出 :‘Could not perform Execute for User’


下面是我的代码
public static User[] GetUser(int _id)
{
SimpleQuery query = new SimpleQuery(
typeof(User),

@"from Users users where users.LogonID = ?",

_id

);


return (User[])ExecuteQuery(query);
}

调用是
User[] blog = User.GetUser(2);

System.Console.WriteLine(blog.Length);

 回复 引用 查看   
#13楼 2006-12-08 16:53 charleschen      
自己又试了下,
public static User[] GetPostsInterval(int cname)
{
//注意:Hql中大小写区分
string hql = @"from User c where c.LogonID=?";
SimpleQuery sq = new SimpleQuery(typeof(User), hql, cname);

return (User[])ExecuteQuery(sq);

}


换成这样又可以了,,,,不知道为什么,郁闷

 回复 引用 查看   
#14楼[楼主] 2006-12-11 23:28 TerryLee      
@charleschen
看看第一个HQL语句:
Users users,有Users这个实体类吗?

 回复 引用   
#15楼 2007-01-25 14:21 jovichina[未注册用户]
hql里面一定要用别名么?如果上面的simplequery里的语句改为@"from Post where Post.Category = ?"就出错“undefined alias or unknown mapping”这是为什么呢
 回复 引用   
#16楼 2007-07-31 10:53 shareach[未注册用户]
我刚开始看castle,看了你ar和ioc部分的文章。我想问一下怎么调用存储过程:
我在存储过程只是简单的对一张表做了个select,但是无法绑定到对象,提示序列化出问题,做了跟踪,发现是ar和hr这层对字段进行了从命名,如 Person 字段 变成了 _Person01之类,不知道有没有解决方法,在实际应用种一些复杂的分析查询还是需要存储过程支持的。谢谢。

 回复 引用   
#17楼 2007-08-03 21:11 firedemoning[未注册用户]
请问题一下.它中的模糊查询什么办.
 回复 引用 查看   
#18楼 2007-08-10 10:12 破甲      
string hql = "From Test test where test.a = ? and teat.b = ? ";
string[] paras = new string[2] {"222","444"};
IActiveRecordQuery<T[]> query = new SimpleQuery<T>(typeof(T), QueryLanguage.Hql, hql, paras);
为什么 paras是数组就不行了!!!

 回复 引用 查看   
#19楼 2008-03-24 12:52 江大鱼      
update 语句能用在 SimpleQuery 里面么?
 回复 引用 查看   
#20楼 2008-05-16 14:44 零缺陷生活      
--引用--------------------------------------------------

--------------------------------------------------------
这个问题怎么没有答复的?

 回复 引用 查看   
#21楼 2008-05-16 14:51 零缺陷生活      
如果我做联合查询,那么返回的数据就不会是一个实体,这个时候我如何把他绑定到一个实体,动态创建一个实体类吗?
============================
这个问题怎么处理???

 回复 引用 查看   
#22楼 2011-06-23 11:50 秦时 明月      
楼主hql和sql有什么区别?
优势在哪里啊?

 回复 引用 查看   
#23楼 2011-10-12 23:39 小徒弟      
@塞月
SimpleQuery query=new SimpleQuery(
typeof(Post),
@"from Post post where post.Contents like ?",
"%"+_content+"%");

return (Post[])ExecuteQuery(query);

新手问点东西

我想问下_content你在哪定义了?_content这个是变量吗?