代码之家  ›  专栏  ›  技术社区  ›  Brant Bobby

如何使用nhibernate icriteria API表示此LINQ查询?

  •  5
  • Brant Bobby  · 技术社区  · 14 年前

    我目前的项目是使用NHibernate 3.0B1和 NHibernate.Linq.Query<T>() 应用程序编程接口。我对Linq相当精通,但我对HQL或ICriteriaAPI完全没有经验。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 描述它的历史。 票务处理 子类型包括 CreateAction , ReassignAction , CloseAction 等等,所有的票都有 创建操作 创建时添加到此集合。

    此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 回复  |  直到 14 年前
        1
  •  2
  •   Josh    14 年前

    试试这个。它是未编译的,但只要 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中,我得到一个尽可能过滤掉的初始结果集,然后用linq再次过滤以得到我需要的结果。

        2
  •  0
  •   Iain    14 年前

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