Hibernate/JPA 单向 OneToMany,连接条件为源中的常量值 table

Hibernate/JPA unidirectional OneToMany with join condition on constant value in source table

我想使用 Hibernate 注释来表示使用连接的单向一对多关系。我想在连接上添加一个条件,因此只有当 source table("one")中的列等于常数值时才会发生。例如.

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

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

我的问题与这个问题非常相似,只是我对来源有条件 table。

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 来自源 table。所以我得到错误:org.hibernate.MappingException: Unable to find column with logical name: 'OFFICE' in buildings

提前致谢!

在我看来,您应该创建一个特定的查询来实现您的目标,而不是使用常量参数放置特定的注释。我没有看到你提到除 Hibernate 之外的其他框架,所以我会举一些 Hibernate 的例子。在您的 Building class 中,您的 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 来执行此操作。希望这可以帮助你实现你的目标。

为什么不使用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;
}

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

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

将其映射到 class OfficeBuildingFloors 作为普通实体,然后在 Building class.

中使用 @OneToMany

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

如果你想要过滤源 table 你可以使用 @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

在数据库中使用视图的方法会更好、更清晰,如果它也可以在数据库中使用。否则将 Building 重命名为明确表示过滤的名称。

提及的另一种方法:@Filter、@FilterDef。