Hibernate在多对多关系中留下了连接约束

时间:2015-08-26 01:33:55

标签: java hibernate join hibernate-criteria

我已经构建了一个可标记文档列表,标记与文档之间存在多对多关系。我现在想使用hibernate标准机制查询每个标记的“摘要”,其中包括特定标记的使用频率计数,以及对文档是否已发布的额外限制。

我正在使用的实体大致如下(你会在中间注意到一个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<>();

}

鉴于上述情况,我已经设法弄清楚构建查询应该或多或少地起作用如下:

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

鉴于上述情况,hibernate生成的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

如上所示,发布约束适用于两个左外连接。我不确定这是否是设计的,但我需要的是将已发布的约束仅应用于第二个左外连接。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

我能够通过侧身来避开这个问题。首先,我必须更改“已发布”列以使用整数而不是一点。然后我能够稍微修改结果的投影,如下所示:

    // 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");
    }

我承认这实际上并没有回答关于为什么多对多表上的hibernate条件约束被应用于所有表的问题,但它解决了我的问题。