如何使用 NHibernate ICriteria API 表达此 LINQ 查询?

发布于 2024-09-29 23:57:34 字数 1239 浏览 2 评论 0原文

我当前的项目使用 NHibernate 3.0b1 和 NHibernate.Linq.Query() 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 子类型包括 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() 方法会引发 NotSupportedException。我可以使用 ICriteria 来完成此操作吗?

My current project is using NHibernate 3.0b1 and the NHibernate.Linq.Query<T>() API. I'm pretty fluent in LINQ, but I have absolutely no experience with HQL or the ICriteria API. One of my queries isn't supported by the IQueryable API, so I presume I need to use one of the previous APIs -- but I have no idea where to start.

I've tried searching the web for a good "getting started" guide to ICriteria, but the only examples I've found are either far too simplistic to apply here or far too advanced for me to understand. If anyone has some good learning materials to pass along, it would be greatly appreciated.

In any case, the object model I'm querying against looks like this (greatly simplified, non-relevant properties omitted):

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; }
}

A Ticket has a collection of TicketAction describing its history. TicketAction subtypes include CreateAction, ReassignAction, CloseAction, etc. All tickets have a CreateAction added to this collection when created.

This LINQ query is searching for tickets created by someone with the given name.

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

The OfType<T>() method causes a NotSupportedException to be thrown. Can I do this using ICriteria instead?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别闹i 2024-10-06 23:57:34

尝试这样的事情。它是未编译的,但只要 IEnumerable就应该可以工作。 ActionsPerson 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 再次过滤以获得我需要的内容。

try something like this. It's uncompiled, but it should work as long as IEnumerable<TicketAction> Actions and Person TakenBy is never null. If you set it to an empty list in the ticket constructor, that will solve a problem with nulls.

If you add a reference to the Ticket object in the TicketAction, you could do something like this:

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;

In my experience, nhibernate has trouble with criteria when it comes to lists when the list is on the object side - such as is your case. When it is a list of values on the input side, you can use Expression.Eq. I've always had to find ways around this limitation through linq, where I get an initial result set filtered down as best as I can, then filter again with linq to get what I need.

风吹过旳痕迹 2024-10-06 23:57:34

支持 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();

OfType is supported. I'm not sure ToUpper is though, but as SQL ignores case it does not matter (as long as you are not also running the query in memory...). Here is a working unit test from the nHibernate.LINQ project:

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);

Perhaps your query should look more like the following:

var animals = (from ticket in session.Linq<Ticket>()
               where ticket.Actions.OfType<CreateAction>().Any(m => m.TakenBy.Name.Contains("john"))
               select ticket).ToArray();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文