让OData和NHibernate结合进行动态查询

简介:

OData是一个非常灵活的RESTful API,如果要做出强大的查询API,那么OData就强烈推荐了。http://www.odata.org/

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的项目在这里:

http://aspnet.codeplex.com/SourceControl/changeset/view/72014f4c779e#Samples/WebApi/NHibernateQueryableSample/System.Web.Http.OData.NHibernate/NHibernateFilterBinder.cs

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 {  getset; } 
      [DataMember] 
       public IList<T> ResultSet {  getset; } 
       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,如需转载请自行联系原作者


相关文章
|
SQL 测试技术 容器
使用 ABAP 代码给 OData 元数据增添注解的一些例子
使用 ABAP 代码给 OData 元数据增添注解的一些例子
一个典型的加了 SAP 注解的 OData 服务明细分析
如下图所示,我有一个 SAP UI5 应用,使用 SAP UI5 SmartTable 控件,消费了一个施加了 sap 命名空间的 OData 服务。关于这个 SAP UI5 应用更多细节,请查看我这篇文章:如何以 mock server 的方式本地启动 SAP UI5 应用,使它不连接服务器端 OData 服务。
一个典型的加了 SAP 注解的 OData 服务明细分析
|
小程序 Windows
SAP C4C OData服务的filter,客户端分页和排序的使用方式
假设系统里已经有许多的Lead历史数据,而我们正在进行的微信小程序和C4C集成的项目里,又创建了许多新的Lead数据。如何将这些新的在微信小程序里调用OData服务创建的Lead数据同老的历史数据做区分呢? (1) 在C4C Sales Lead页面里,通过Source字段来标明Lead的来源。
SAP C4C OData服务的filter,客户端分页和排序的使用方式
|
SQL 关系型数据库 C#