0

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.

Community
  • 1
  • 1
Farhan stands with Palestine
  • 13,890
  • 13
  • 58
  • 105

1 Answers1

3

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

@OneToMany(cascade = CascadeType.ALL)

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>();

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 identifiers.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • Same exception still persists. Please suggest. – Farhan stands with Palestine Jan 07 '17 at 17:03
  • Try changing the @Id from int to Integer – Vlad Mihalcea Jan 07 '17 at 17:14
  • Same exception after using the wrapper classes too. – Farhan stands with Palestine Jan 07 '17 at 17:16
  • Since the mapping is bidirectional, the exception suggests - The unsaved transient entity must be saved in an operation prior to saving these dependent entities. As seen clearly, both are PERSON and ADDRESS entities are cross-dependent on one another. Its a deadlock. The exception occurs on - `session.save(address1);` before `session.save(address2); session.save(person1);` Any suggestions. – Farhan stands with Palestine Jan 07 '17 at 17:23
  • Thanks Vlad, I am able to achieve the join table structure though composite key. – Farhan stands with Palestine Jan 08 '17 at 08:13
  • Vlad - But don't you think that using Join tables on both the sides of the mapping was also correct, even though it didn't create the desired table structure with exceptions being thrown too. Had a look at the one of the questions posted http://stackoverflow.com/questions/9360626/bidirectional-one-to-many-with-jointable with the OP suggesting that indeed using Join tables on both sides of the mapping does work. Suggestions any... – Farhan stands with Palestine Jan 08 '17 at 08:43
  • It could be a Hibernate bug. Try opening an issue and send a [replicating test case](http://in.relation.to/2016/01/14/hibernate-jpa-test-case-template/). – Vlad Mihalcea Jan 08 '17 at 09:27
  • OKay, I will for sure. BTW, as you are working with RedHat, do you look after the issues with Hibernate ORM? – Farhan stands with Palestine Jan 08 '17 at 09:30
  • I'm working for Red Hat, yes. As for the issue, it will be fixed based on its priority. If you submit a Pull Request, it will be integrated very fast ;) – Vlad Mihalcea Jan 08 '17 at 09:43