我目前的项目是使用NHibernate 3.0b1和NHibernate.Linq.Query<T>()
API。我对LINQ非常流利,但我对HQL或ICriteria API没有任何经验。 IQueryable API不支持我的一个查询,因此我认为我需要使用以前的API之一 - 但我不知道从哪里开始。
我已经尝试在网上搜索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; }
}
Ticket
有一个描述其历史记录的TicketAction
集合。 TicketAction
个子类型包括CreateAction
,ReassignAction
,CloseAction
等。所有故障单在创建时都会添加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代替吗?
答案 0 :(得分:2)
尝试这样的事情。它是未编译的,但只要IEnumerable<TicketAction> Actions
和Person TakenBy
永远不为空,它就应该有效。如果在票证构造函数中将其设置为空列表,则可以解决空值问题。
如果您在TicketAction中添加对Ticket对象的引用,您可以执行以下操作:
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过滤以获得我需要的东西。
答案 1 :(得分: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();