Я пытаюсь написать адаптер hibernate для старой схемы базы данных. Эта схема не имеет выделенного столбца идентификатора, но использует три других столбца для объединения данных.
На некоторых таблицах мне нужно использовать coalesce. Это то, к чему я придумал:
Об определении:
- Автомобиль может иметь элементы, назначенные пользователем автомобиля или группой пользователей автомобилей.
- Если FORIGN_ELEMENT содержит имя пользователя, определение будет "u"
- Если FORIGN_ELEMENT содержит имя группы, определение будет "g"
- Это также означает, что одна таблица (CAR_TO_ELEMENT) используется неправильно для сопоставления автомобилей с элементами и группами cargroups. Я определил класс CarElement и подклассы CarUserElement и CarGroupElement. Состояние
- является либо "активной", либо неинтересной строкой
- Я установил определенность и положение в другом месте, нам не нужно беспокоиться об этом.
- Используйте DEP_NR в таблице соединений. Если он равен нулю, используйте USR_DEP_NR. Я сделал это с
COALESCE(NULLIF())
успешно в родном SQL и хочу добиться того же в Hibernate с Pojos.
Хорошо, вот мы идем с кодом:
@Entity
@Table(name="CAR")
public class Car extends TableEntry implements Serializable {
@Id
@Column(name="DEP_NR")
private int depnr;
@Id
@Column(name="USER_NAME")
@Type(type="TrimmedString")
private String username;
@ManyToOne(fetch = FetchType.EAGER, targetEntity=CarGroup.class)
@JoinColumns(value={
@JoinColumn(name="GROUP_NAME"),
@JoinColumn(name="DEP_NR"),
@JoinColumn(name="state"),
})
private CarGroup group;
@OneToMany(fetch=FetchType.EAGER, targetEntity=CarUserElement.class, mappedBy="car")
private Set<CarUserElement> elements;
}
@Entity
@Table(name="CAR_GROUP")
public class CarGroup extends TableEntry implements Serializable {
@Id
@Column(name="DEP_NR")
private int depnr;
@Id
@Column(name="GROUP_NAME")
@Type(type="TrimmedString")
private String group;
@ManyToOne(fetch = FetchType.EAGER, targetEntity=Car.class)
@JoinColumns(value={
@JoinColumn(name="GROUP_NAME"),
@JoinColumn(name="DEP_NR"),
@JoinColumn(name="state"),
})
private Set<Car> cars;
@OneToMany(fetch=FetchType.EAGER, targetEntity=CarGroupElement.class, mappedBy="car")
private Set<CarGroupElement> elements;
}
@MappedSuperclass
public class CarElement extends TableEntry {
@Id
@ManyToOne(fetch = FetchType.EAGER, targetEntity=Element.class)
@JoinColumns(value={
@JoinColumn(name="ELEMENT_NAME"),
@JoinColumn(name="state"),
})
private Element element;
}
@Entity
@Table(name="CAR_TO_ELEMENT")
public class CarUserElement extends CarElement {
@Id
@Column(name="DEFINITION")
private char definition;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumnsOrFormulas(value = {
@JoinColumnOrFormula([email protected](value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
@JoinColumnOrFormula([email protected](name="FORIGN_ELEMENT", referencedColumnName="USER_NAME")),
@JoinColumnOrFormula([email protected](name="STATE", referencedColumnName="STATE"))
})
private Car car;
}
@Entity
@Table(name="CAR_TO_ELEMENT")
public class CarGroupElement extends CarElement {
@Id
@Column(name="DEFINITION")
private char definition;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumnsOrFormulas(value = {
@JoinColumnOrFormula([email protected](value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
@JoinColumnOrFormula([email protected](name="FORIGN_ELEMENT", referencedColumnName="GROUP_NAME")),
@JoinColumnOrFormula([email protected](name="STATE", referencedColumnName="STATE"))
})
private Car car;
}
Я пробовал все доступные версии hibernate (от 3.5.1 [первая версия с @JoinColumnsOrFormulas
] до 4.x.x), но я всегда получаю эту ошибку:
Exception in thread "main" java.lang.ClassCastException: org.hibernate.mapping.Formula cannot be cast to org.hibernate.mapping.Column
at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:351)
at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1338)
at org.hibernate.cfg.annotations.CollectionBinder.bindOneToManySecondPass(CollectionBinder.java:791)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:719)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:668)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:66)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1597)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1355)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1737)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1788)
У других пользователей спящего режима, похоже, есть одна и та же проблема: они не могут заставить его работать с какой-либо версией, см. этот поток и другие вопросы, касающиеся stackoverflow: https://forum.hibernate.org/viewtopic.php?f=1&t=1010559
Чтобы быть более полным, вот мой класс TrimmedString: https://forum.hibernate.org/viewtopic.php?p=2191674&sid=049b85950db50a8bd145f9dac49a5f6e#p2191674
Спасибо заранее!
PS: Он работает с объединением только этих трех столбцов только с одним DEP-NR-столбцом (т.е. DEP_NR OR USR_DEP_NR, используя только @JoinColumns). Но мне нужно это COALESCE(NULLIF())
.