NHibernate是一个流行的.NET框架下的ORM(对象关系映射)工具,它通过将数据库中的表映射到.NET对象,使得开发者能够以面向对象的方式来处理数据库操作。NHibernate的设计遵循了关注点分离原则,确保了工作单元(Unit Of Work)和其配置(实体和映射)之间的分离。虽然手动编写映射类可能会让一些开发者感到复杂,但NHibernate和Entity Framework一样,都支持POCO(Plain Old CLR Object)实体的创建。对于ORM来说,最重要的就是从数据库中检索数据的方式,以及在处理大量数据时优化响应时间。本文将介绍NHibernate中的两种查询API:Criteria API和QueryOver API。
为了理解这两种查询API的区别,需要有一定的FluentNHibernate经验。Fluent NHibernate是一个NHibernate的映射框架,它使用流畅的接口来定义映射,使得映射过程更加直观和灵活。
作为ORM,NHibernate操作的是对象而不是表。使用Criteria API进行查询是简单、直观且可扩展的。要使用Criteria查询API,首先需要创建一个NHibernate.ICriteria
的新实例,它与一个持久化实体关联,并代表对其的查询。例如,对于一个Person
实体:
ICriteria criteria = currentSession.CreateCriteria<Person>();
可以对这个标准进行操作,以获取想要的结果。如果想要获取所有Person
的列表:
currentSession.CreateCriteria(typeof(Person)).List<Person>();
或者可以通过调用实例来实现:
criteria.List<Person>();
如果想要根据ID搜索一个Person
,例如:
Person person = currentSession.Get<Person>(id);
或者:
Person person = criteria.Get<Person>(id);
这些结果可以通过应用限制到Criteria查询来过滤。因此,使用Restrictions
工厂类,它定义了ICriteria
接口上可用的一系列方法,并将它们传递给Add
方法。
让看一个例子:
Criteria.Add(Restrictions.Eq("Name", "Rayen"));
或者可以实例化一个新的对象,它具有类型IQueryCriterion
限制。
var restrictions = new Conjunction(); restrictions.Add(new LikeCriterion<A>(c => c.Name, "Rayen", true, MatchingMode.Anywhere));
如果想要相等,可以调用第二个方法:
restrictions.Add(new EqualCriterion<A>(c => c.Name, "Rayen"));
这是LikeCriterion
方法:
private LikeCriterion(Expression<Func<A, object>> propertyExpression, string value, bool insensitive, MatchingMode matchMode) {
PropertyExpression = propertyExpression;
Value = value;
MatchMode = matchMode;
Insensitive = insensitive;
}
public EqualCriterion(Expression<Func<A, object>> propertyExpression, object value) {
PropertyExpression = propertyExpression;
Value = value;
}
var persons = currentSession.CreateCriteria(typeof(Person)).Add(restrictions);
在这个例子中,引入了Expression
的概念,它可以被分组。可以使用NHibernate.Expression.Order
来排序结果。
var personOrdered = criteria.AddOrder(Order.Asc("Name")).SetMaxResults(100).List<Person>();
可以使用Projections
,它使用工厂类NHibernate.Expression.Projections IProjection
实例。它通过调用SetProjection()
方法来应用。工厂方法允许通过标准和顺序实例引用投影值。
这是一个获取计数的例子:
public int GetCount(IQueryCriterion restrictions) {
var criteria = _currentSession.CreateCriteria(typeof(T)).SetProjection(Projections.RowCount);
return (int)criteria.UniqueResult();
}
Criteria API在构建动态查询方面非常强大,这有助于提高应用程序中的搜索效率。但是,正如在示例中看到的,属性在criteria查询中是硬编码的。因此,将使用QueryOver来增强criteria查询。
让重写之前的示例,但通过集成QueryOver。
criteria.List<Person>();
criteria.QueryOver<Person>().List();
var persons = currentSession.CreateCriteria(typeof(Person)).Add(restrictions);
var persons = currentSession.QueryOver<Person>().Where(restrictions).List();
QueryOver使用Where
,它类似于SQL查询,它包括许多特性,例如TransformUsing
,它使用提供的IResultTransformer
转换结果。
IResultTransformer
是一个实现者,它定义了一种策略,用于将criteria查询结果转换为实际应用程序可见的查询结果列表。
可以使用OrderBy
:
IEnumerable<T> GetAllOrderBy(Expression<Func<T, bool>> restrictions, Expression<Func<T, object>> order, bool ascending = false);
在IRepository
中有一个方法:
实现将在Repository
类中。
public IEnumerable<T> GetAllOrderBy(Expression<Func<T, bool>> restrictions, Expression<Func<T, object>> orderByProperty, bool ascending = false) {
var query = currentSession.QueryOver<T>().Where(restrictions);
return ascending ? query.OrderBy(orderByProperty).Asc.List() : query.OrderBy(orderByProperty).Desc.List();
}
其中T
是Person
。
var Persons = _personRepository.GetAllOrderBy(e => e.Name == "Rayen", e => e.CreationTime, true);