你的位置:首页 > ASP.net教程

[ASP.net教程]让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 { 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的错误。目前还没有找到解决办法。


去黑龙江的旅游团价格去黑龙江旅游必去景点去黑龙江旅游要多少钱去黑龙江旅游最佳路线去黑龙江旅游最佳时间风采迷人的关中八景 咸阳古渡 风采迷人的关中八景 灞柳风雪 风采迷人的关中八景 草堂烟雾 澳大利亚昆士兰州抱考拉实用攻略![三] 2015年广东街坊文化节开幕式什么时候?广州街坊文化节举办地点在哪里? 华南植物园街坊欢乐节什么时候?广州华南植物园街坊欢乐节时间? 华南植物园中秋游园会活动时间?广州华南植物园中秋游园会有什么好玩的? 广州街坊文化节在哪里开幕?广东街坊文化节来华南植物园吗? 5月份去大觉山漂流冷吗?江西大觉山漂流最佳漂流时间? 北京到红海滩廊道自驾车路线?北京到红海滩风景廊道多长时间? 沈阳到盘锦红海滩自驾车路线?沈阳到盘锦红海滩廊道开车怎么走? 沈阳到盘锦红海滩廊道怎么走?沈阳到盘锦红海滩有多远? 天涯海角在哪个省? 三亚免税店在哪里?要注意什么吗? 桂林四绝是什么? 冬天怎么玩好? 553-0002-846 Datasheet 553-0002-846 Datasheet 553-0002-846F Datasheet 553-0002-846F Datasheet 553-0002-847 Datasheet 553-0002-847 Datasheet 石家庄去港澳旅游 石家庄去港澳旅游 石家庄去港澳旅游 齐齐哈尔去香港迪士尼游 齐齐哈尔去香港迪士尼游 齐齐哈尔去香港迪士尼游 大连去香港旅游 大连去香港旅游 大连去香港旅游