NHibernate - QueryOver 查询


在本章中,我们将介绍 QueryOver 查询。它是一种新语法,更像是使用方法链语法的 LINQ,如以下查询所示。

var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "Laverne");
  • 它仍然是幕后的标准,但现在我们的查询是强类型的。

  • 正如我们在条件查询中看到的,名字只是一个不透明的字符串,现在我们实际上使用的是 x.FirstName ,因此名字被重构并重命名,并在链接样式条件查询中使用以下查询进行更改。

  • 我们仍然可以做很多类似的事情,但是你不能将查询理解语法与 query over 一起使用,你必须使用方法链语法,并且不能混合和匹配链接和条件。

  • 对于很多查询来说,通过 API 进行查询非常有用,并且提供了比直接使用 Criteria 更容易理解的对象语法。

让我们看一个简单的示例,在该示例中我们将使用查询来检索名字为 Laverne 的客户。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
      
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var customers = session.QueryOver<Customer>() 
               .Where(x => x.FirstName == "Laverne"); 
            
            foreach (var customer in customers.List()) { 
               Console.WriteLine(customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
      
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize();
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         });
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

正如您所看到的,它的本质仍然是 Criteria,但只是一种更好的语法。

当上面的代码被编译并执行时,您将看到以下输出。

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

缺点之一是,假设我们想说FirstName.StartsWith(“A”),如以下程序所示。

var customers = session.QueryOver<Customer>() .Where(x => x.FirstName.StartsWith("A"));
 
foreach (var customer in customers.List()) { 
   Console.WriteLine(customer); 
} 

tx.Commit();

现在让我们再次运行该应用程序,您将看到这不是 LINQ 提供程序,因为它不知道StartsWith方法是什么,因此您将收到一个RunTime 异常

运行时异常

异常表示无法识别的方法调用。在这里,我们正在做显而易见的事情,但它不一定有效。

让我们尝试其他方法,例如 FirstName 等于“A%”,如以下代码所示。

var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "A%"); 

foreach (var customer in customers.List()) { 
   Console.WriteLine(customer); 
}

让我们再次运行此命令,您将看到我们不会返回任何结果,如下所示。

Press <ENTER> to exit...

为了理解为什么我们没有得到任何结果,让我们看一下 NHibernate 分析器。

结果 NHibernate 简介

正如您所看到的,名字等于 A%,但事实并非如此。A% 在 SQL 中与 like 运算符一起使用。现在我们需要在 WHERE 子句中创建限制,如以下程序所示。

var customers = session.QueryOver<Customer>() 
   .Where(Restrictions.On<Customer>(c => c.FirstName).IsLike("A%")); 
	
foreach (var customer in customers.List()) { 
   Console.WriteLine(customer); 
}

让我们再次运行您的应用程序,您将看到检索到名字以 A 开头的所有客户。

Alejandrin Will (4ea3aef6-6bce-11e1-b0b4-6cf049ee52be)
   Points: 24
   HasGoldStatus: False
   MemberSince: 10/1/2011 12:00:00 AM (Utc)
   CreditRating: VeryVeryGood
   AverageRating: 0

   Orders:
      Order Id: 4ea3aef6-6bce-11e1-b0b5-6cf049ee52be

Austyn Nolan (4ea871b6-6bce-11e1-b110-6cf049ee52be)
   Points: 67
   HasGoldStatus: True
   MemberSince: 12/29/2007 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea871b6-6bce-11e1-b111-6cf049ee52be

Antonia Murphy (4ea871b6-6bce-11e1-b121-6cf049ee52be)
   Points: 72
   HasGoldStatus: True
   MemberSince: 6/15/2009 12:00:00 AM (Utc)
   CreditRating: Terrible
   AverageRating: 0

   Orders:
      Order Id: 4ea871b6-6bce-11e1-b122-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b123-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b124-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b125-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b126-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b127-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b128-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b129-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b12a-6cf049ee52be

除了使用新的QueryOver语法之外,它的工作方式与以前相同。许多开发人员发现 LINQ 语法更平易近人,并且通常可以做正确的事情。

如果 LINQ 无法处理它,那么您将开始查看 HQL 或 Criteria,看看是否更合适。

它只是为您提供了不同的语法,因此 Criteria、创建条件和 QueryOver 都为您提供了另一种查询机制,允许您使用 NHibernate 从数据库中提取数据。