1

I have the following 2 classes:

@Entity
@Table(name = "TableA")
public class EntityA
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    private final Integer id = null;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "BId")
    private EntityB b;

    public EntityA(EntityB b)
    {
        this.b = b;
    }
}

@Entity
@Table(name = "TableB")
public class EntityB
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    private final Integer id = null;

    @OneToOne(mappedBy = "b")
    private final EntityA a = null;
}

When I do

session.save(new EntityA(new EntityB());

the database only inserts a record in TableA and leaves the column that references TableB as NULL

If I first insert b, then a, it works, but it should work with a single call too.

Other questions/answers mention that the annotations are not correct, but I see no difference between mine and the provided solutions.

I also tried adding the CascadeType.PERSIST on both @OneToOne annotations, but that didnt work either.

Wietlol
  • 1,001
  • 1
  • 10
  • 25
  • What errors are raised with and without CascadeType annotations? – Klaimmore Mar 17 '18 at 14:35
  • with the current setup, there are no errors, just no records for TableB, before, I had the column in SQLServer set to NOT NULL, and then I got insertion errors saying that I cannot insert with NULL values for BId – Wietlol Mar 17 '18 at 14:37
  • Ah, I see, I had to use CascadeType.ALL instead of... any combination of the others actually, with ALL on the @OneToOne, it worked – Wietlol Mar 17 '18 at 14:50
  • 1
    @Wietlol thats because you are not using JPA's entityManager to persist but instead Hibernate's session so you have to either use Hibernate's `org.hibernate.annotations.CascadeType.SAVE_UPDATE`or if you use JPA's @CascadeType if you use ALL it will cover Hibernate's cascades as well. Look [here](https://www.mkyong.com/hibernate/cascade-jpa-hibernate-annotation-common-mistake/) and [here](https://stackoverflow.com/q/4540806/8068435) for more info. – Ranjeet Mar 17 '18 at 19:56
  • That seems to be the answer, can you provide it as an answer so I can mark it as the solution? Also, would it be better to use the entity manager instead of the hibernate session? I kind of went into this with "It just has to work" so I can choose to use something other than hibernate if it will reduce the complexity or errors in setting things up – Wietlol Mar 17 '18 at 22:10
  • @Wietlol Yes it is better to stick with one thing either JPA or Hibernate. Unless something isnt possible with JPA, I dont see any reason to use the Hibernate session. My Advice try using JPA for all your needs. In case something isnt possible via JPA you can always get the session via `Session session = em.unwrap(Session.class);` – Ranjeet Mar 22 '18 at 08:17
  • Just be sure to use fully qualified names for Hibernate in your code for Hibernate annotations and classes so that with one look at the code and you will know what is deviating from JPA (Since there are many classes with same names in JPA and Hibernate's namespace). Example : `org.hibernate.Query query = session.createQuery(queryString)` – Ranjeet Mar 22 '18 at 08:20

2 Answers2

0

In jpa, default Cascade setting is NONE ... thus the entities in relationships (B in your case) is not inserted (persisted) by default ... You need to annotate the relationship with @OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.PERSIST)

osama yaccoub
  • 1,884
  • 2
  • 17
  • 47
  • the issue i had is that even with PERSIST, it still didnt work. since cascase can take a list of types, i tried adding more and more, but ONLY with CascaseTyoe.ALL, it worked, nothing else – Wietlol Mar 17 '18 at 18:09
0

First of all you must delete final keyword from your entities. Try this one:

@Entity
@Table(name = "TableA")
class EntityA {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    private Integer id;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name = "BId")
    private EntityB b;


    public Integer getId() {
        return id;
    }


    public void setId(Integer id) {
        this.id = id;
    }


    public EntityB getB() {
        return b;
    }


    public void setB(EntityB b) {
        this.b = b;
    }


    public EntityA(EntityB b) {
        this.b = b;
        b.setA(this);
    }
}

@Entity
@Table(name = "TableB")
class EntityB {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    private Integer id;

    @OneToOne(mappedBy = "b")
    private EntityA a;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public EntityA getA() {
        return a;
    }

    public void setA(EntityA a) {
        this.a = a;
    }
}

I am using spring boot, hibernate and H2 database

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        ApplicationContext app =  SpringApplication.run(DemoApplication.class, args);
        ServiceCascade bean = app.getBean(ServiceCascade.class);
        bean.save();
    }
}

@Service
class ServiceCascade {
    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public void save() {
        EntityA entityA = new EntityA(new EntityB());
        entityManager.persist(entityA);
    }
}

The following logs show that the two entities are inserted correctly

org.hibernate.SQL : insert into tableb (id) values (null)
org.hibernate.SQL : insert into tablea (id, bid) values (null, ?)
o.h.type.descriptor.sql.BasicBinder  : binding parameter [1] as [INTEGER] - [1]
SEY_91
  • 1,615
  • 15
  • 26
  • This did not work, as I mentioned, I tried adding CascadeType.PERSIST to both sides already. CascadeType.ALL seems to work though, and @Cascade from org.hibernate.annotation (as Ranjeet mentioned) also works. – Wietlol Mar 17 '18 at 22:12
  • I use the Session::save from hibernate, the entity manager does work for me – Wietlol Mar 17 '18 at 22:24