【问题标题】:Nhibernate Where Exists queryOverNhibernate Where Exists queryOver
【发布时间】:2013-01-21 19:40:07
【问题描述】:

我有以下物品

public class Document
{
    public Guid Id { get; set; }
    public ISet<Tag> Tags { get; set;}
    ...
}

public class Tag 
{
    public Guid Id { get; set;} 
}

这是多对多关系,但我没有中间 DocumentTag 对象。 我正在尝试使用 QueryOver 语法来返回具有所有一组标签的所有文档。这是我到目前为止所拥有的。

Guid[] tagsThatMustMatch = ...;
var result = Session.QueryOver<Document>()
               .WithSubquery
               .WhereExists(QueryOver.Of<Tag>().Where(t => tagsThatMustMatch.Contains(t.Id))
               .List()

我无法表达需求。我知道我必须动态构建一个查询,该查询将为每个必须匹配的标签提供一个 WhereExists。这些 WhereExists 需要进行与运算。我遇到的另一个问题是 WhereExists 方法需要接受 DetachedQuery。但是我没有办法限制它只看这个文档没有所有标签的标签。

是否有任何示例可以让我了解如何执行此类操作?

【问题讨论】:

    标签: nhibernate queryover


    【解决方案1】:

    使用 IN - 无需调整实体定义

    让我们首先以这种方式声明您的子查询:

    Guid[] tagsThatMustMatch = ...;
    
    var subQuery = QueryOver.Of<Tag>()
     .WhereRestrictionOn(t => t.Id).IsIn(tagsThatMustMatch)
      .Select(t => t.Id); // tag ID projection
    

    有了分离的条件,我们可以像这样在 QueryOver 语法中使用它们:

    var query = session.QueryOver<Document>()
      .JoinQueryOver<Tag>(d => d.Tags)
      .Where(Subqueries.PropertyIn("Id", subQuery.DetachedCriteria)) // Tag.Id
      // .TransformUsing(Transformers.DistinctRootEntity) // distinct
      ; 
    

    扩展:

    使用 EXISTS - 需要在我们的实体域模型中进行调整

    正如Diego Jancic 在他的评论中指出的那样,EXISTS 可能更有效......但前提是有从TagDocument 的引用

    可能是参考

    public class Tag 
    {
        public Guid Id { get; set;} 
        public Document Document { get; set; }
    }
    

    或至少是代表文档 ID 的 Guid

    public class Tag 
    {
        public Guid Id { get; set;} 
        public Guid DocumentId { get; set; }
    }
    

    假设第一个,然后我们可以像这样使用子查询

    Guid[] tagsThatMustMatch = ...;
    
    // Essential alias of the parent Document
    Document document = null;
    
    var subQuery = QueryOver.Of<Tag>()
     .Where(t => t.Document.Id == document.Id) // or t.DocumentId = document.Id
     .WhereRestrictionOn(t => t.Id).IsIn(tagsThatMustMatch)
     .Select(t => t.Id); // tag ID projection
    

    这是唯一的方法,子查询如何仅在与文档相关的标签上正确返回 true。存在的查询看起来像这样

    var query = session
        .QueryOver<Document>(() => document) // alias used in subquery
        .WithSubquery                        // needed to filter by parent id
            .WhereExists(subQuery)
        ...
    

    【讨论】:

    • -1 因为有 3 个问题:1) 他要求EXISTS,而不是INJOIN,2) 做X IN (select Id from T where Id IN (...)) 与做@987654334“几乎”相同@ 和 3) 使用 JOIN 这样做很慢,应该使用 EXIST
    • @DiegoJancic,我用你建议的方法扩展了我的答案。这不是那么微不足道,因为我们必须扩展域模型才能实现它,但现在它会做(正如你提到的) 更好的 sql 语句。非常感谢您评论为什么不赞成。我很佩服你附上了评论!感谢您帮助改进它
    • 谢谢。很好的答案。改为 +1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    相关资源
    最近更新 更多