让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的错误。目前还没有找到解决办法。

分享给朋友:
您可能感兴趣的文章:
随机阅读: