2010-10-29 63 views
5

我目前的项目是使用NHibernate 3.0b1和NHibernate.Linq.Query<T>() API。我在LINQ中很流利,但我对HQL或ICriteria API完全没有经验。我的一个查询不支持IQueryable API,所以我认为我需要使用以前的API之一 - 但我不知道从哪里开始。如何使用NHibernate ICriteria API表示这个LINQ查询?

我试过在网络上搜索ICriteria的一个很好的入门指南,但是我发现的唯一例子要么太简单化以至于无法在这里应用,要么我的理解太过先进。如果有人有一些很好的学习材料传递,将不胜感激。

在任何情况下,对象模型,我询问对这个样子的(大大简化,不相关的特性省略):

class Ticket { 
    IEnumerable<TicketAction> Actions { get; set; } 
} 
abstract class TicketAction { 
    Person TakenBy { get; set; } 
    DateTime Timestamp { get; set; } 
} 
class CreateAction : TicketAction {} 
class Person { 
    string Name { get; set; } 
} 

一个TicketTicketAction集合描述它的历史。 TicketAction亚型包括CreateActionReassignActionCloseAction等。所有门票在创建时都会将CreateAction添加到此集合中。

此LINQ查询正在搜索具有给定名称的人创建的票据。

var createdByName = "john".ToUpper(); 
var tickets = _session.Query<Ticket>() 
    .Where(t => t.Actions 
     .OfType<CreateAction>() 
     .Any(a => a.TakenBy.Name.ToUpper().Contains(createdByName)); 

OfType<T>()方法使NotSupportedException被抛出。我可以使用ICriteria来代替吗?

回答

2

尝试这样的事情。它是未编译的,但它应该工作,只要IEnumerable<TicketAction> ActionsPerson TakenBy永远不为空。如果将它设置为票据构造函数中的空列表,那将解决空值问题。

如果添加到在TicketAction票据对象的引用,你可以做这样的事情:

ICriteria criteria = _session.CreateCriteria(typeof(CreateAction)) 
    .Add(Expression.Eq("TakenBy.Name", createdByName)); 

var actions = criteria.List<CreateAction>(); 

var results = from a in criteria.List<>() 
    select a.Ticket; 

以我的经验,NHibernate的有标准的麻烦,当谈到名单时,名单上对象方面 - 比如你的情况。当它是输入端的值列表时,可以使用Expression.Eq。我总是不得不通过linq找到解决这个限制的方法,在那里我得到了一个尽可能最好的过滤结果集,然后再用linq过滤以获得我所需要的。

+0

我宁愿没有到反向引用添加到'TicketAction'的'Ticket'如果我可以帮助它,因为这会引入其他问题,但谢谢你的提示。 :) – 2010-11-01 14:32:22

+0

我们处理这种情况的另一种方式是实际在字符串生成器中创建HQL。我们尝试使用Linq到Nhibernate表达式,但是当集合位于对象一侧时,它们也不支持集合。不幸的是,“包含”方法不能通过Linq转换为nHibernate。 – Josh 2010-11-01 16:48:08

+0

毕竟我的建议是(在TicketAction上添加对Ticket的引用),但最终出现错误:“NHibernate.QueryException:无法解析属性:TakenBy。名称:CreateAction“ – 2010-11-01 21:13:47

0

OfType受支持。我不确定ToUpper是什么,但是由于SQL忽略大小写并不重要(只要你不在内存中运行查询......)。下面是从nHibernate.LINQ项目一个工作单元测试:

var animals = (from animal in session.Linq<Animal>() 
       where animal.Children.OfType<Mammal>().Any(m => m.Pregnant) 
       select animal).ToArray(); 
Assert.AreEqual("789", animals.Single().SerialNumber); 

也许你的查询应该看起来更像是以下几点:

var animals = (from ticket in session.Linq<Ticket>() 
       where ticket.Actions.OfType<CreateAction>().Any(m => m.TakenBy.Name.Contains("john")) 
       select ticket).ToArray();