与JPA注解的双向@OneToMany关系似乎不起作用 [英] Bidirectional @OneToMany relation with JPA annotations doesn't seem to work

查看:1813
本文介绍了与JPA注解的双向@OneToMany关系似乎不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是参考这个

实体 -



//多对一

p>

  @Entity 
@Table
公共类地址{

@Id
@GeneratedValue
@Column
private int addressIdentity;

@Column
private int houseNo;

@Column
private char streetNo;

@Column
private int pincode;

@Column
私人字符串城市;

@Column
私有字符串状态;

@Column
私人字符串国家;

@ManyToOne
@JoinTable(name =PersonAddress,
joinColumns = @ JoinColumn(name =addressId,insertable = false,updatable = false),
)joinJoinColumns = @ JoinColumn(name =personId,insertable = false,updatable = false)

private Person person;
// getters and setters






一对多

  @Entity 
@Table
public class Person {

@Id
@GeneratedValue
@Column
private int personId;

@Column
私人字符串名称;

@Column
私人字符串指定;
$ b @OneToMany
@JoinTable(name =PersonAddress,
joinColumns = @JoinColumn(name =personId),
inverseJoinColumns = @JoinColumn(name = addressId))
private Set< Address> addSet = new HashSet< Address>();
// getters和setters



Hibernate配置文件 -

 < hibernate-configuration> 
< session-factory name =>
< property name =hibernate.connection.driver_class> org.postgresql.Driver< / property>
< property name =hibernate.connection.password> hello< / property>
< property name =hibernate.connection.url> jdbc:postgresql:// localhost:5432 / xyz< / property>
< property name =hibernate.connection.username> postgres< / property>
< property name =hibernate.dialect> org.hibernate.dialect.PostgreSQLDialect< / property>
< property name =show_sql> true< / property>
< property name =hbm2ddl.auto>建立< / property>
< mapping class =ManyToOne_OneToManyMappingWithJoinTable.Person/>
< mapping class =ManyToOne_OneToManyMappingWithJoinTable.Address/>
< / session-factory>
< / hibernate-configuration>






持久性逻辑 -

  SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); 
Session session = sessionFactory.openSession();
session.beginTransaction();

Person person1 = new Person();
person1.setName(Shahnaz Parveen);
person1.setDesignation(HouseWife);

地址address1 =新地址();
address1.setHouseNo(18);
address1.setStreetNo('E');
address1.setPincode(250002);
address1.setCity(Meerut);
address1.setState(UP);
address1.setCountry(INDIA);
address1.setPerson(person1);

地址address2 =新地址();
address2.setHouseNo(84);
address2.setStreetNo('1');
address2.setPincode(250002);
address2.setCity(Meerut);
address2.setState(UP);
address2.setCountry(INDIA);
address1.setPerson(person1);

person1.getAddSet()。add(address1);
person1.getAddSet()。add(address2);

session.save(address1);
session.save(address2);
session.save(person1);

session.getTransaction()。commit();
session.close();



我得到 -



'pre> 2017年1月7日下午九时47分35秒org.hibernate.action.internal.UnresolvedEntityInsertActions logCannotResolveNonNullableTransientDependencies
WARN:HHH000437:试图保存一个或多个实体与未保存的瞬态实体具有不可空的关联。未保存的瞬态实体必须在保存这些从属实体之前保存在操作中。
未保存的临时实体:([ManyToOne_OneToManyMappingWithJoinTable.Person#0])
从属实体:([[ManyToOne_OneToManyMappingWithJoinTable.Address#1]])
不可为空的关联(S):([ManyToOne_OneToManyMappingWithJoinTable .Address.person])在螺纹
异常主 org.hibernate.TransientPropertyValueException:非空属性引用瞬态值 - 瞬态的实例必须保存beforeQuery当前操作:ManyToOne_OneToManyMappingWithJoinTable.Address.person - > ManyToOne_OneToManyMappingWithJoinTable.Person
at org.hibernate.action.internal.UnresolvedEntityInsertActions.checkNoUnresolvedActionsAfterOperation(UnresolvedEntityInsertActions.java:122)
at org.hibernate.engine.spi.ActionQueue.checkNoUnresolvedActionsAfterOperation(ActionQueue.java:418)
。在org.hibernate.internal.SessionImpl.checkNoUnresolvedActionsAfterOperation(SessionImpl.java:621)
处org.hibernate作为org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:684)
。在许多OneToManyMappingWithJoinTable.ManyToOne_OneToManyMappingWithJoinTableImpl.main(ManyToOne_OneToManyMappingWithJoinTableImpl.java:40)
(org.hibernate.internal.SessionImpl.save(SessionImpl.java:669))
(SessionImpl.java:674)

它适用于hbms。

请建议。






感谢Vlad和Neil,它可以工作,但是有一个问题 -



这是用HBM创建的结构。

  CREATE TABLE person_address 

addressid integer NOT NULL,
PERSONID整数NOT NULL,
约束person_address_pkey PRIMARY KEY(addressid,PERSONID),
约束fkkpp6mysmnyiywx3q33yxr1gbe外键(PERSONID)
参考人(为person_id)MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
约束fkrpk0jx2y558su288tx9kd5cs6外键(addressid)
参考地址(ADDRESS_ID)MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION

现在我做 -

  @OneToMany(cascade = CascadeType.ALL,mappedBy =person)
private Set< Address> addSet = new HashSet< Address>();

连接表结构是 -



<$ p
personid integer,
addressid integer NOT NULL,
CONSTRAINT personaddress_pkey PRIMARY KEY(addressid),
CONSTRAINT (personid)
REFERENCES person(personid) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION

您会看到主键不像HBM中的 addressid和personid 的组合。请提出建议。

解决方案

您需要添加级联的一对多方:

  @OneToMany(cascade = CascadeType.ALL)

查看这篇文章
$ b

然后,将 @ManyToOne 一边更改为:

  @ManyToOne 
@JoinTable(name =PersonAddress,
joinColumns = @ JoinColumn(name =addressId),
reverseJoinColumns = @ JoinColumn(name =personId)

私人person person;

@OneToMany / p>

  @OneToMany(cascade = CascadeType.ALL,mappedBy =person)
private Set< Address> addSet = new HashSet< Address>();



更新



如问题更新所示,请尝试将连接表(例如 personaddress )映射为实体,并使用复合键,如本文


This is in reference to this answer.

Entities-

// Many to One

@Entity
@Table
public class Address {

    @Id
    @GeneratedValue
    @Column
    private int addressIdentity;

    @Column
    private int houseNo;

    @Column
    private char streetNo;

    @Column
    private int pincode;

    @Column
    private String city;

    @Column
    private String state;

    @Column
    private String country;

    @ManyToOne
       @JoinTable(name="PersonAddress", 
            joinColumns=@JoinColumn(name="addressId", insertable = false, updatable = false),
            inverseJoinColumns=@JoinColumn(name="personId", insertable = false, updatable = false)
       )
    private Person person;
    // getters and setters


One to Many

@Entity
@Table
public class Person {

    @Id
    @GeneratedValue
    @Column
    private int personId;

    @Column
    private String name;

    @Column
    private String designation;

    @OneToMany
    @JoinTable(name = "PersonAddress", 
                            joinColumns = @JoinColumn(name = "personId"), 
                                inverseJoinColumns = @JoinColumn(name = "addressId"))
    private Set<Address> addSet = new HashSet<Address>();
    // getters and setters


Hibernate configuration file-

<hibernate-configuration>
    <session-factory name="">
        <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
        <property name="hibernate.connection.password">hello</property>
        <property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/xyz</property>
        <property name="hibernate.connection.username">postgres</property>
        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="show_sql">true</property>
        <property name="hbm2ddl.auto">create</property>
        <mapping class="ManyToOne_OneToManyMappingWithJoinTable.Person" />
        <mapping class="ManyToOne_OneToManyMappingWithJoinTable.Address" />
    </session-factory>
</hibernate-configuration>


the persistence logic-

        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();

        Person person1 = new Person();
        person1.setName("Shahnaz Parveen");
        person1.setDesignation("HouseWife");

        Address address1 = new Address();
        address1.setHouseNo(18);
        address1.setStreetNo('E');
        address1.setPincode(250002);
        address1.setCity("Meerut");
        address1.setState("UP");
        address1.setCountry("INDIA");
        address1.setPerson(person1);

        Address address2 = new Address();
        address2.setHouseNo(84);
        address2.setStreetNo('1');
        address2.setPincode(250002);
        address2.setCity("Meerut");
        address2.setState("UP");
        address2.setCountry("INDIA");
        address1.setPerson(person1);

        person1.getAddSet().add(address1);
        person1.getAddSet().add(address2);

        session.save(address1);
        session.save(address2);
        session.save(person1);

        session.getTransaction().commit();
        session.close();


I am getting -

Jan 07, 2017 9:47:35 PM org.hibernate.action.internal.UnresolvedEntityInsertActions logCannotResolveNonNullableTransientDependencies
WARN: HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. The unsaved transient entity must be saved in an operation prior to saving these dependent entities.
    Unsaved transient entity: ([ManyToOne_OneToManyMappingWithJoinTable.Person#0])
    Dependent entities: ([[ManyToOne_OneToManyMappingWithJoinTable.Address#1]])
    Non-nullable association(s): ([ManyToOne_OneToManyMappingWithJoinTable.Address.person])
Exception in thread "main" org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved beforeQuery current operation : ManyToOne_OneToManyMappingWithJoinTable.Address.person -> ManyToOne_OneToManyMappingWithJoinTable.Person
    at org.hibernate.action.internal.UnresolvedEntityInsertActions.checkNoUnresolvedActionsAfterOperation(UnresolvedEntityInsertActions.java:122)
    at org.hibernate.engine.spi.ActionQueue.checkNoUnresolvedActionsAfterOperation(ActionQueue.java:418)
    at org.hibernate.internal.SessionImpl.checkNoUnresolvedActionsAfterOperation(SessionImpl.java:621)
    at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:684)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:674)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:669)
    at ManyToOne_OneToManyMappingWithJoinTable.ManyToOne_OneToManyMappingWithJoinTableImpl.main(ManyToOne_OneToManyMappingWithJoinTableImpl.java:40)

It works perfect with hbms.

Please suggest.


Thanks Vlad and Neil, it works but there is a problem described below-

This is the structure which gets created with HBMs. Hence the same must be with Annotations.

CREATE TABLE person_address
(
  addressid integer NOT NULL,
  personid integer NOT NULL,
  CONSTRAINT person_address_pkey PRIMARY KEY (addressid , personid ),
  CONSTRAINT fkkpp6mysmnyiywx3q33yxr1gbe FOREIGN KEY (personid )
      REFERENCES person (person_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fkrpk0jx2y558su288tx9kd5cs6 FOREIGN KEY (addressid )
      REFERENCES address (address_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

the moment I do -

@OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
private Set<Address> addSet = new HashSet<Address>();

the join table structure is-

CREATE TABLE personaddress
(
  personid integer,
  addressid integer NOT NULL,
  CONSTRAINT personaddress_pkey PRIMARY KEY (addressid),
  CONSTRAINT fkfd5pm843bldj10y5kxwo37xge FOREIGN KEY (addressid)
      REFERENCES address (addressidentity) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fkjuwlthwsi53bpf902nnl6snxh FOREIGN KEY (personid)
      REFERENCES person (personid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

You see that the primary key is NOT a combination of addressid and personid as in HBMs. Please suggest.

解决方案

You need to add a cascade the one-to-many side:

@OneToMany(cascade = CascadeType.ALL)

Check out this article for more details.

Then, change the @ManyToOne side to:

@ManyToOne
@JoinTable(name="PersonAddress", 
    joinColumns=@JoinColumn(name="addressId"),
    inverseJoinColumns=@JoinColumn(name="personId")
)
private Person person;

and the @OneToMany side to:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
private Set<Address> addSet = new HashSet<Address>();

Update

To address the composite-key requirement as indicated by the question update, try mapping the join table (e.g. personaddress) as an entity, and use composite keys as explained in this article.

这篇关于与JPA注解的双向@OneToMany关系似乎不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆