• 让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。 

  • 相关阅读:
    推荐!国外程序员整理的 PHP 资源大全
    PHPSTORM/IntelliJ IDEA 常用 设置配置优化
    PHPStorm下XDebug配置
    MySQL修改root密码的多种方法
    php 修改上传文件大小 (max_execution_time post_max_size)
    phpstorm8注册码
    Linux提示no crontab for root的解决办法
    网站的通用注册原型设计
    解决mysql出现“the table is full”的问题
    通过php下载文件并重命名
  • 原文地址:https://www.cnblogs.com/studyzy/p/5462868.html
Copyright © 2020-2023  润新知