Hibernateアノテーションを使用して、結合を使用した一方向の1対多の関係を表現したいと思います。結合に条件を追加して、sourceテーブル(「1」)の列が定数値に等しい場合にのみ発生するようにします。例えば。
SELECT *
FROM buildings b
LEFT JOIN building_floors bf on bf.building_id = b.id AND b.type = 'OFFICE'
そのクエリのb.type = 'OFFICE'
部分を表現したいと思います。
私の質問は、ソーステーブルに条件があることを除いて、これと非常によく似ています。 JPA /定数値でのHibernate結合
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
}
私はそのプレースホルダーコメントがあるいくつかのことを試しました:
これはターゲットエンティティに適用されるため、機能しません。
@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({
@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
前もって感謝します!
継承 を使用しないのはなぜですか? (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 bf.* FROM building_floors bf JOIN buildings b on bf.building_id = b.id AND b.type = 'OFFICE'
それを通常のエンティティとしてクラスOfficeBuildingFloors
にマップしてから、Building
クラスで@OneToMany
を使用します。
もちろん、そのようなコレクションを変更することはできません。例外を回避するために、OfficeBuildingFloors
で@Immutable
を使用できます。
フィルタソーステーブルが必要な場合は、@ 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。
私の意見では、定数パラメーターを使用して特定のアノテーションを配置するのではなく、目標を達成するために特定のクエリを作成する必要があります。 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で実行できます。これがあなたの目標を達成するのに役立つことを願っています。