#hibernate #derived
#спящий режим #производный
Вопрос:
У меня есть две таблицы A и B с отношением «один ко многим». В обеих таблицах есть поле идентификатора, которое автоматически увеличивается. В таблице B также есть поле внешнего ключа, ссылающееся на поле идентификатора таблицы A.
Вот схема таблицы для базы данных MySQL:
CREATE TABLE A (
`id` INT NOT NULL AUTO_INCREMENT,
`afield` varchar(255),
PRIMARY KEY (`id`)
) ;
CREATE TABLE B (
`id` INT NOT NULL AUTO_INCREMENT,
`aId` INT NOT NULL,
`bfield` varchar(255),
PRIMARY KEY (`id`),
FOREIGN KEY (`aId`)REFERENCES A(`id`) ON DELETE CASCADE
) ;
Классы:
@Entity
@Table(name = "A")
public class A implements java.io.Serializable {
private Integer id;
private String aField;
private List b;
public A() {}
public A(Integer id) {
this.id = id;
}
@Id
@Column(name = "id", unique = true, nullable = false)
@GenericGenerator(name = "generator", strategy = "native")
@GeneratedValue(generator = "generator")
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "AFIELD", length = 50)
public String getAField() {
return this.aField;
}
public void setAField(String aField) {
this.aField = aField;
}
//mapped by = "a" a is a field in B. Case sensetive @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "a")
public List getB() {
return b;
}
public void setB(List b) {
this.b = b;
}
}
@Entity
@Table(name = "B")
public class B implements java.io.Serializable {
private String bField;
private Integer id;
private Integer aId;
private A a;
public B() {}
@Id
@Column(name = "id", unique = true, nullable = false)
@GenericGenerator(name = "generator", strategy = "native")
@GeneratedValue(generator = "generator")
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "aId")
public Integer getAId() {
return this.aId;
}
public void setAId(Integer aId) {
this.aId = aId;
}
@Column(name = "BFIELD", length = 50)
public String getBField() {
return this.bField;
}
public void setBField(String bField) {
this.bField = bField;
}
@ManyToOne
@JoinColumn(name = "aId", insertable = false, updatable = false)
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
Ниже приведен мой метод тестирования:
public static void main(String[] args) {
try {
Configuration cfg = new Configuration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session sess = factory.getCurrentSession();
Transaction tx = sess.beginTransaction();
A a = new A();
a.setAField("afield");
// sess.save(a);
// sess.flush();
List < B > bs = new ArrayList < B > ();
a.setB(bs);
B b = new B();
b.setBField("bfield");
// b.setAId(a.getId());
bs.add(b);
sess.saveOrUpdate(a);
tx.commit();
factory.close();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
С включенными тремя закомментированными строками все работает нормально. В основном он получает идентификатор от объекта a и устанавливает его в объект b.
Но я не рад, что мне нужно сохранить объект, прежде чем сохранять список объектов b. Есть ли в любом случае, что это будет работать без трех закомментированных строк? Сценарий заключается в том, что другие люди могут просто создать объект a и задать объект списка b, а затем сохранить объект a, поскольку они не знают деталей взаимосвязи двух объектов, и они также не знают схемы.
Любая помощь приветствуется!
Ответ №1:
Пожалуйста, пожалуйста, потратьте некоторое время на форматирование вашего вопроса, прежде чем отправлять его.
Тем не менее: aId
столбец в таблице B отображается дважды: один раз для aId
поля и один раз для a
. Этот aId
столбец должен исчезнуть. У вас должна быть только ассоциация от B до A. Если вам нужен идентификатор формы B, просто позвоните b.getA().getId()
.
Другим важным моментом является то, что у вас двунаправленная ассоциация. Вы должны убедиться, что граф сущностей является согласованным. если вы добавляете B в список Bs A, вы также должны установить поле A в B :
a.getBs().add(b);
b.setA(a);
Hibernate просматривает только одну сторону ассоциации, чтобы знать, что нужно сохранить. Эта сторона — та, у которой нет этого mappedBy
атрибута. Это означает, что вам абсолютно необходимо позвонить b.setA(a)
, чтобы заставить его работать.
Комментарии:
1. Спасибо за ответ. Боюсь, я заблудился. Вы сказали, что для его сохранения мне нужно использовать b.setA(a). На самом деле мне вообще не нужно этого делать для нормальной ситуации. Мне нужно только установить список B в A, чтобы оба A и B сохранялись без проблем. Проблема возникает только тогда, когда aId является первичным ключом A и генерируется изначально.
2. Посмотрите в docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/… как предполагается сопоставить двунаправленную ассоциацию «один ко многим». Сторона-владелец — это та сторона, которую использует Hibernate, чтобы решить, существует ли ассоциация или нет. Он должен быть инициализирован.