首页 文章

Hibernate / JPA单向OneToMany,在源表中具有常量值的连接条件

提问于
浏览
15

我想使用Hibernate注释来表示使用连接的单向一对多关系 . 我想在连接上添加一个条件,这样只有当源表中的列("one")等于一个常量值时才会发生这种情况 . 例如 .

SELECT *
FROM buildings b
LEFT JOIN building_floors bf on bf.building_id = b.id AND b.type = 'OFFICE'

我想表示该查询的 b.type = 'OFFICE' 部分 .

我的问题与这个问题非常相似,只是我在源表上有一个条件 . JPA/Hibernate Join On Constant Value

Java实体看起来像这样:

@Entity
@Table(name = "buildings")
public class Building {

    @Id
    @Column(name = "id")
    private int id;

    @Column(name = "type")
    private String type;

    @OneToMany(mappedBy = "buildingId",
            fetch = FetchType.EAGER,
            cascade = {CascadeType.ALL},
            orphanRemoval = true)
    @Fetch(FetchMode.JOIN)
    // buildings.type = 'OFFICE'   ????
    private Set<BuildingFloors> buildingFloors;

    // getters/setters
}

@Entity
@Table(name = "building_floors")
public class BuildingFloor {

    @Id
    @Column(name = "building_id")
    private int buildingId;

    @Id
    @Column(name = "floor_id")
    private int floorId;

    @Column(name = "description")
    private String description;

    // getters/setters
}

我尝试了一些我有占位符评论的东西:

@Where注释

这不起作用,因为它适用于目标实体 .

@JoinColumns注释

@JoinColumns({
        @JoinColumn(name = "building_id", referencedColumnName = "id"),
        @JoinColumn(name = "'OFFICE'", referencedColumnName = "type")
})

这不起作用,因为我得到以下错误(为简洁起见而简化): Syntax error in SQL statement "SELECT * FROM buildings b JOIN building_floors bf on bf.building_id = b.id AND bf.'OFFICE' = b.type"

不同的@JoinColumns注释

@JoinColumns({
        @JoinColumn(name = "building_id", referencedColumnName = "id"),
        @JoinColumn(name = "buildings.type", referencedColumnName = "'OFFICE'")
})

这不起作用,因为在使用单向OneToMany关系时,referencedColumnName来自源表 . 所以我得到错误: org.hibernate.MappingException: Unable to find column with logical name: 'OFFICE' in buildings

提前致谢!

4 回答

  • 1

    如您所希望的过滤器源表,您可以使用@Loader注释

    @Entity
    @Table(name = "buildings")
    @Loader(namedQuery = "building")
    @NamedNativeQuery(name="building", 
        query="SELECT * FROM buildings b"
            + " LEFT JOIN building_floors bf on bf.building_id = b.id"
            + " WHERE b.type = 'OFFICE' AND b.id = ?",
        resultClass = Building.class)
    class Building
    

    如果可以在DB内部使用,那么在DB中查看的方法会更好更清楚 . 否则将Building重命名为明确表示过滤的内容 .

    另一种提法:@Filter,@ FilterDef .

  • 1

    使用以下选择创建数据库视图:

    SELECT bf.* FROM building_floors bf JOIN buildings b on bf.building_id = b.id AND b.type = 'OFFICE'

    将它作为普通实体映射到类 OfficeBuildingFloors ,然后在 Building 类中使用 @OneToMany .

    当然,您将无法修改此类集合并避免在 OfficeBuildingFloors 上使用 @Immutable 的任何异常 .

  • 8

    为什么不使用inheritance? (我用它与JPA,我从不直接使用hibernate)

    @Entity
    @Inheritance
    @Table(name = "buildings")
    @DiscriminatorColumn(name="type")
    public class Building {
    
        @Id
        @Column(name = "id")
        private int id;
    
        @Column(name = "type")
        private String type;
    }
    

    而且:

    @Entity
    @DiscriminatorValue("OFFICE")
    public class Office extends Building {
        @OneToMany(mappedBy = "buildingId",
            fetch = FetchType.EAGER,
            cascade = {CascadeType.ALL},
            orphanRemoval = true)
        private Set<BuildingFloors> buildingFloors;
    }
    
  • 4

    在我看来,你应该创建一个特定的查询来实现你的目标,而不是使用常量参数放置特定的注释 . 我没有看到你提到除了Hibernate之外的其他框架,所以我会举一些Hibernate的例子 . 在 Building 类中, unidirectional 映射看起来像这样:

    @OneToMany(fetch = FetchType.Lazy, cascade = {CascadeType.ALL}, orphanRemoval = true)
    @JoinTable(name = "building_floors", joinColumns = @JoinColumn(name = "id"), inverseJoinColumns = @JoinColumn(name = "building_id")
    private Set<BuildingFloor> buildingFloors;
    

    然后,您可以像这样使用 TypedQuery 获取数据 .

    TypedQuery<Customer> query = getEntityManager().createNamedQuery("select b from building b inner join fetch b.buildingFloors where b.type = 'OFFICE'", Building.class);
    List<Building> result = query.getResultList();
    

    我的解决方案不是特定于Hibernate的,实际上你可以用简单的JPA来执行它 . 希望这可以帮助您实现目标 .

相关问题