简体   繁体   English

多对多关系中的Hibernate左联接约束

[英]Hibernate left join constraint in a many-to-many relationship

I have built a list of taggable documents, with a many-to-many relationship between the tags and the documents. 我建立了一个可标记文档列表,标签和文档之间具有多对多关系。 I would now like to use the hibernate criteria mechanism to query a "summary" of each tag, which includes a count of how often a particular tag has been used, with an additional restriction on whether or not the document has been published. 我现在想使用休眠标准机制来查询每个标签的“摘要”,其中包括对使用特定标签的频率的计数,并对是否已发布文档有一个额外的限制。

The entities I'm using roughly look like this (You'll note an SQL join table in the middle there): 我正在使用的实体大致如下所示(您会在中间注意到一个SQL连接表):

@Entity
public class DocumentTag {

    ... various things ...

    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "tags")
    private List<Document> documents = new ArrayList<>();

}

@Entity
public class Document {

    ... various things ...

    @Basic
    @Column(name = "published", columnDefinition = "BIT", length = 1)
    protected boolean published = false;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "document_tag_joins",
            uniqueConstraints = @UniqueConstraint(
                    columnNames = {"document", "tag"}
            ),
            joinColumns = {@JoinColumn(name = "document")},
            inverseJoinColumns = {@JoinColumn(name = "tag")})
    private List<DocumentTag> tags = new ArrayList<>();

}

Given the above, I've managed to figure out that building the query should work more or less as follows: 鉴于以上所述,我设法弄清楚了构建查询应该或多或少地如下工作:

Criteria c = session.createCriteria(DocumentTag.class);

c.createAlias("documents", "docs",
        JoinType.LEFT_OUTER_JOIN,
        Restrictions.eq("published", true)
);

c.setProjection(
        Projections.projectionList()
                .add(Projections.alias(Projections.groupProperty("id"), "id"))
                .add(Projections.alias(Projections.property("createdDate"), "createdDate"))
                .add(Projections.alias(Projections.property("modifiedDate"), "modifiedDate"))
                .add(Projections.alias(Projections.property("name"), "name"))
                .add(Projections.countDistinct("docs.id"), "documentCount"));

// Custom response entity mapping
c.setResultTransformer(
        Transformers.aliasToBean(DocumentTagSummary.class)
);

List<DocumentTagSummary> results = c.list();

Given the above, the hibernate generated SQL query looks as follows: 鉴于以上所述,休眠生成的SQL查询如下所示:

SELECT
  this_.id                AS y0_,
  this_.createdDate       AS y1_,
  this_.modifiedDate      AS y2_,
  this_.name              AS y3_,
  count(DISTINCT doc1_.id) AS y5_
FROM tags this_ 
  LEFT OUTER JOIN tag_joins documents3_
    ON this_.id = documents3_.tag AND (doc1_.published = ?)
  LEFT OUTER JOIN documents doc1_
    ON documents3_.document = doc1_.id AND (doc1_.published = ?)
GROUP BY this_.id

As you can see above, the publishing constraint is applied to both of the left outer joins. 如上所示,发布约束同时应用于两个左外部联接。 I'm not certain whether that is by design, however what I need is for the published constraint to be applied ONLY to the second left outer join. 我不确定这是否是设计使然,但是我需要的是将发布的约束仅应用于第二个左外部联接。

Any ideas? 有任何想法吗?

I was able to circumvent this problem by coming at it sideways. 我可以通过横向解决这个问题。 First, I had to change the "published" column to use an integer rather than a bit. 首先,我必须将“已发布”列更改为使用整数而不是一点。 Then I was able to slightly modify the projection of the result as follows: 然后,我可以对结果的投影进行如下修改:

    // Start building the projections
    ProjectionList projections =
            Projections.projectionList()
                    .add(Projections.alias(
                            Projections.groupProperty("id"), "id"))
                    .add(Projections.alias(
                            Projections.property("createdDate"),
                            "createdDate"))
                    .add(Projections.alias(
                            Projections.property("modifiedDate"),
                            "modifiedDate"))
                    .add(Projections.alias(
                            Projections.property("name"), "name"));

    if (isAdmin()) {
        // Give the raw count.
        projections.add(Projections.countDistinct("docs.id"), "documentCount");
    } else {
        // Use the sum of the "published" field.
        projections.add(Projections.sum("docs.published"), "documentCount");
    }

I acknowledge that this doesn't actually answer the question about why hibernate criteria constraints on many-to-many tables get applied to all tables, but it solved my problem. 我承认这并没有真正回答关于为什么多对多表上的休眠条件约束适用于所有表的问题,但这解决了我的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM