简体   繁体   English

休眠,无法保存多对一关系

[英]hibernate, can not save many to one relationship

I've been studying tutorials of @ManyToOne hibernate annotation, but don't fully understand something. 我一直在研究@ManyToOne休眠注释的教程,但是并没有完全了解。 To explain simply, here is piece of code: 为了简单说明,这是一段代码:

@Entity
@Table
public class Student {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column
private String name;
@OneToMany(mappedBy = "student", fetch = FetchType.LAZY)
private Set<Book> bookList;
// getters, setters...
}

and

@Entity
@Table(name = "book")
public class Book {

@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "NAME", unique = true, nullable = false, length = 100)
private String name;
@Column(name = "DESCRIPTION", unique = true, nullable = false, length = 100)
private String description;
@ManyToOne(fetch = FetchType.LAZY, optional = true)
@JoinTable(name = "CATALOG", joinColumns = @JoinColumn(name = "ID_BOOK"),  inverseJoinColumns = @JoinColumn(name = "ID_STUDENT"))
private Student student;
// getters, setters...
}

and, when on those two classes I execute: 并且,当在这两个类上执行时:

Session session = factory.getCurrentSession();
    //start
    System.out.println("start!");
    Book book = new Book();
    book.setName("bulk");
    book.setDescription("hulk");
    //book set
    session.beginTransaction();
    session.save(book);
    //book saved
    Student stud = new Student();
    stud.setName("Mark");
    //stud set
    Set<Book> books = new HashSet<>();
    book.setStudent(stud);
    books.add(book);
    //book add to list
    stud.setBookList(books);
    //list added to stud
    session.save(stud);

    session.getTransaction().commit();

the result is obviously: 结果显然是:

start!
Hibernate: insert into book (DESCRIPTION, NAME) values (?, ?)
Hibernate: insert into Student (name) values (?)
Hibernate: insert into CATALOG (ID_STUDENT, ID_BOOK) values (?, ?)
end

Now when I do the same (in my opinion, obviously, else it would work) with these two classes: 现在,当我对这两个类进行相同的操作(我认为很明显,其他方法也可以):

@Entity
@Table(name = "client",
    uniqueConstraints = {
        @UniqueConstraint(columnNames = {"client_id"})})
public class Client {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "client_id", nullable = false, unique = true, length = 11)
private int id;
@Column(name = "client_name", length = 60, nullable = true)
private String name;
@Column(name = "client_comment", length = 60, nullable = true)
private String comment;
@Column(name = "client_activated", nullable = true)
private boolean activated;

@OneToMany(mappedBy = "client", fetch = FetchType.LAZY)
Set<AdditionalProperty> propertiesList;

// start of class properties

@Entity
@Table(name = "user_properties",
    uniqueConstraints = {
        @UniqueConstraint(columnNames = {"property_id"})})
public class AdditionalProperty {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "property_id")
private int id;
@Column(name = "property_name", length = 60, nullable = true)
private String name;
@Column(name = "property_type", length = 60, nullable = true)
private String propertyType;
//@ManyToOne(cascade = CascadeType.ALL)
//@JoinColumn(name = "property_to_client")
//@ManyToOne(fetch = FetchType.LAZY,optional=true)
//@JoinTable(name = "ref_client_to_property", joinColumns = @JoinColumn(name = "ref_property_id"), inverseJoinColumns = @JoinColumn(name = "ref_client_id"))
@ManyToOne(fetch = FetchType.LAZY, optional = true)
@JoinTable(name = "ref_client_to_prop", joinColumns = @JoinColumn(name = "id_prop"), inverseJoinColumns = @JoinColumn(name = "id_client"))
private Client client;

when I execute this code: 当我执行此代码时:

AdditionalProperty prop = new AdditionalProperty();
    prop.setName("testf2");
    prop.setPropertyType("testt2");
    AdditionalProperty prop2 = new AdditionalProperty();
    prop2.setName("wat2");
    prop2.setPropertyType("wat");
    //props set
    new HibernateDAOAdditionalProperty().create(prop);
    new HibernateDAOAdditionalProperty().create(prop2);
    System.out.println("prop set");
    //props saved


    Client client = new Client();
    client.setName("cascadeable");
    client.setComment("ho-ho-ho");
    client.setActivated(false);
    //cli set
    Set<AdditionalProperty> propList = new HashSet<>();
    prop.setClient(client);
    prop2.setClient(client);
    propList.add(prop);
    propList.add(prop2);
    // props added to list
    client.setPropertiesList(propList);
    // list added to client
    HibernateDAOClient dao = new HibernateDAOClient();
    dao.create(client);

the result in query is not what I expect: 查询的结果不是我期望的:

Hibernate: insert into user_properties (property_name, property_type) values (?, ?)
Hibernate: insert into user_properties (property_name, property_type) values (?, ?)
prop set
Hibernate: insert into client (client_activated, client_comment, client_name) values (?, ?, ?)

Where I expect: 我期望的地方:

Hibernate: insert into ref_client_to_prop (id_client, id_prop) values (?, ?)

Please help, what am I doing wrong? 请帮助,我在做什么错? I need to save their relationship in database, but somehow I can't. 我需要将他们之间的关系保存在数据库中,但是不知何故。

PS to add to confusion: PS增添混乱:

when I use this class: 当我使用此类时:

public class ClientProperty {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="id_client")
private Client client;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="id_characteristic")
private AdditionalProperty property;
@Column(name = "characteristic_value")
private String value;

and then execute (add to previous piece of code): 然后执行(添加到前面的代码中):

System.out.println("try to save");
    ClientProperty cliPro = new ClientProperty();
    cliPro.setClient(client);
    cliPro.setProperty(prop);
    cliPro.setValue("vocabulary");
    DAOInterface<ClientProperty> daocp = new HibernateDAOClientProperty();
    daocp.create(cliPro);

I magically get exactly what I want. 我神奇地得到了我想要的。 Don't know how. 不知道怎么做

Hibernate: insert into client_characteristic_filled (id_client, id_characteristic, characteristic_value) values (?, ?, ?)
Hibernate: update client set client_activated=?, client_comment=?, client_name=? where client_id=?
Hibernate: update user_properties set property_name=?, property_type=? where property_id=?
Hibernate: update ref_client_to_prop set id_client=? where id_prop=?
Hibernate: insert into ref_client_to_prop (id_client, id_prop) values (?, ?)

In the first case, you're setting the book's student while inside a transaction, on a book that you just saved from the same transaction. 在第一种情况下,您是在交易中将这本书的学生设置在刚从同一交易中保存的书上。 The Book is thus attached to the session. 因此,该书将附加到会话中。 So Hibernate tracks all the changes to its state, and when you commit, it notices that the book(s client has been set, and thus saves the association. 因此,Hibernate会跟踪其状态的所有更改,并且在您提交时,它会注意到已经设置了该书(客户端),从而保存了关联。

In the second case, you don't have any transaction. 在第二种情况下,您没有任何交易。 You create a property, and as soon as the DAO's transaction is done, the property becomes a detached object, ie a plain old object that Hibernate doesn't know about, whose state isn't tracked at all. 创建一个属性,DAO的事务完成后,该属性将成为一个分离的对象,即Hibernate不知道的纯旧对象,其状态根本不会被跟踪。 Then you set the property's client on this detached object. 然后,在此分离的对象上设置属性的客户端。 But Hibernate doesn't know anything about that, and it thus doesn't insert the association. 但是Hibernate对此一无所知,因此不会插入关联。

Note that setting the properties of the client and saving the client doesn't save the association, because the owning side of the bidirectional association is Property.client , not Client.properties . 请注意,设置客户端的属性并保存客户端不会保存关联,因为双向关联的拥有方是Property.client ,而不是Client.properties And Hibernate only cares about the owning side. 而Hibernate只关心所有者。

Avoid using detached objects as much as you can. 尽量避免使用分离的对象。 Start a transaction at the beginning of your business method, then use Hibernate, with only attached objects, then commit the transaction. 在业务方法的开头启动事务,然后使用仅带有附加对象的Hibernate,然后提交事务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM