Hibernate / JPA однонаправленная OneToMany с условием соединения по постоянному значению в исходной таблице
Я хочу использовать аннотации Hibernate для представления однонаправленного отношения "один ко многим" с помощью соединения. Я хочу добавить условие на соединение, чтобы это происходило только тогда, когда столбец в источник таблица ("единица") равна постоянному значению. Например.
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 аннотации
@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 ответов
почему бы не использовать наследование ? (Я использую его с 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
как обычный объект, а затем используйте @OneToMany
за это Building
класса.
конечно, вы не сможете изменить такую коллекцию и избежать каких-либо исключений, которые вы можете использовать @Immutable
on OfficeBuildingFloors
.
на мой взгляд, вы должны создать конкретный запрос для достижения своих целей, а не ставить аннотации с постоянным параметром. Я не вижу, чтобы вы упоминали другие фреймворки, кроме 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();
мои решения не специфичны для гибернации, на самом деле вы можете выполнить это с помощью простой JPA. Надеюсь, это поможет вам достичь ваших целей.
Как вы хотите фильтровать исходную таблицу, вы можете использовать аннотацию @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
подход с видом в БД был бы лучше и понятнее, если бы его можно было использовать и внутри БД. В противном случае переименуйте здание в то, что явно представляет фильтрацию.
другие подходы к упоминанию: @Filter, @FilterDef.