OData是一个非常灵活的RESTful API,如果要做出强大的查询API,那么OData就强烈推荐了。
OData的特点就是可以根据传入参数动态生成Entity Framework的查询,最终实现动态的SQL的查询。但是在项目有时我们并没有采用Entity Framework,而是采用的NHibernate,那么该怎么用OData呢?
经过一段时间的Google和研究,终于找到了一个好的方案。
在OData API查询时,用户前端是url跟参数,但是在服务器端,我们是接收到的是一个ODataQueryOptions<T>对象,其实我们需要做的就是把这个对象进行解析,生成NHibernate能够理解的查询形式,比如HQL。网上找到微软官方已经写了这么个转换方法,主要是对ODataQueryOptions对象下的Filter和OrderBy进行转换,另外两个参数Top和Skip很简单,就是一个整数。
public static string ToHql(
this ODataQueryOptions query,
out int top,
out int skip)
{
string queryString =
" from " + query.Context.ElementClrType.Name +
" $it " + Environment.NewLine;
if (query.Filter !=
null)
{
// convert $filter to HQL where clause. string where = ToString(query.Filter);
queryString +=
where;
}
if(query.OrderBy!=
null)
{
// convert $orderby to HQL orderby clause. string orderBy = ToString(query.OrderBy);
// create a query using the where clause and the orderby clause. queryString += orderBy;
}
top = query.Top?.Value ??
0;
skip = query.Skip?.Value ??
0;
return queryString;
}
ODataQueryOptions转换为HQL的项目在这里:
Filter和OrderBy属性都会被转换成HQL,然后我们就需要进行NHibernate的查询了。
public QueryResult<T> FindByPaging(
string hql,
int top,
int skip)
{
bool paging = top >
0;
var query = Session.CreateQuery(hql);
var querys = Session.CreateMultiQuery();
if (paging)
{
query = query.SetFirstResult(skip).SetMaxResults(top);
}
querys.Add(query);
if (paging)
{
var countQuery = Session.CreateQuery(
" select count(*) " + hql);
querys.Add(countQuery);
}
var queryResults = querys.List();
var result =
new QueryResult<T>();
result.TotalCount = paging
? Convert.ToInt32( ((IList) queryResults[
1])[
0])
: ((IList) queryResults[
0]).Count;
result.ResultSet = ((IList) queryResults[
0]).Cast<T>().ToList();
return result;
}
对于一般的分页查询来说,我们应该会有两个查询,一个是查询满足条件的数据总条数,另一个是返回当前页的数据集。但是似乎OData并不支持返回这样的数据类型,OData支持的是Entity的List,如果我们重新定义了一个对象QueryResult:
[DataContract]
public class QueryResult<T>
{
[DataMember]
public int TotalCount {
get;
set; }
[DataMember]
public IList<T> ResultSet {
get;
set; }
public QueryResult()
{ }
public QueryResult(
int count, IList<T> list)
{
this.TotalCount = count;
this.ResultSet = list;
}
}
然后在Controller中返回QueryResult,那么系统就会报406的错误。其实系统给我们提供了一个专门分页返回的对象System.Web.Http.OData.PageResult<T>,我们可以将Service返回的QueryResult封装成PageResult再返回即可。
PageResult里面有个NextPage的URI参数,我们可以传Null。
本文转自深蓝居博客园博客,原文链接:http://www.cnblogs.com/studyzy/p/5462868.html,如需转载请自行联系原作者