Можно ли заполнить производный автоматически увеличиваемый идентификатор для отношения «многие к одному»?

#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, чтобы решить, существует ли ассоциация или нет. Он должен быть инициализирован.