1

Given a table (MY_TABLE_A) that automatically increments it's id upon each new insertion (i.e. the first record in the database has it's ID attribute 1, the second record has it's ID attribute set to 2, the third record has it's ID attribute set to 3). The ID I am talking about is the table's primary key.

I also have another table (MY_TABLE_B) that reference's the original table's primary key. When I try to persist both to my Oracle database, I get a org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save()

What I want to accomplish: Whenever I persist an object to MY_TABLE_A, I want MY_TABLE_B to insert an object with the same ID that MY_TABLE_A gets since it's auto incremented (wouldn't know what the next value is until it's inserted). To clarify, one id in Table A should have only one matching ID in Table B

Here are some snippets of my code below:

FirstClass:

@Entity
@Table(name = "MY_SCHEMA.MY_TABLE_A")
@Component
public class FirstClass implements Serializable {

    @Id
    @SequenceGenerator(name = "MY_SEQ", sequenceName = "MY_SCHEMA.MY_SEQ", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MY_SEQ")
    @Column(name = "MY_ID")
    private Integer myId;
    // more variables, getters/setters
}

SecondClass:

@Entity
@Table(name = "MY_SCHEMA.MY_TABLE_B")
@SecondaryTable(name = "MY_SCHEMA.MY_TABLE_A", pkJoinColumns = @PrimaryKeyJoinColumn(name = "MY_ID", referencedColumnName = "MY_ID"))
@Component
public class SecondClass {

    @Id
    @Column(name = "MY_ID")
    private Integer myId;
    // more variables, getters/setters
}

Service Layer snippet where I insert new entries for each in Oracle:

firstClassService.insert();
secondClassService.insert();

Details on insert() for firstClassService:

public void insert() {
        FirstClass obj = new FirstClass();
        getCurrentSession().persist(obj);
}

insert() for secondClassService:

public void insert() {
        SecondClass obj = new SecondClass();
        getCurrentSession().persist(obj);
}

UPDATE

What FirstClass looks like now:

@Entity
@Table(name = "MY_SCHEMA.MY_TABLE_A")
@Component
public class FirstClass implements Serializable {

    @Id
    @SequenceGenerator(name = "MY_SEQ", sequenceName = "MY_SCHEMA.MY_SEQ", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MY_SEQ")
    @Column(name = "MY_ID")
    @OneToOne(mappedBy = "myId")
    private Integer myId;
}

SecondClass:

@Entity
@Table(name = "MY_SCHEMA.MY_TABLE_B")
@SecondaryTable(name = "MY_SCHEMA.MY_TABLE_B", pkJoinColumns = @PrimaryKeyJoinColumn(name = "MY_ID", referencedColumnName = "MY_ID"))
@Component
public class SecondClass implements Serializable {

    @Id
    @JoinColumn(name = "MY_ID", referencedColumnName = "MY_ID")
    @OneToOne
    private Integer restRequestId;
}
abhi
  • 1,760
  • 1
  • 24
  • 40

3 Answers3

5

Mappings should be as below:

@Entity
@Table(name = "MY_SCHEMA.MY_TABLE_A")
@Component
public class FirstClass implements Serializable {

    @Id
    @SequenceGenerator(name = "MY_SEQ", sequenceName = "MY_SCHEMA.MY_SEQ", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MY_SEQ")
    @Column(name = "MY_ID")
    private Long myId;

    @OneToOne(mappedBy = "firstClass", cascade = CascadeType.ALL)
    private SecondClass secondClass;
}

@Entity
@Table(name = "MY_SCHEMA.MY_TABLE_B")
@Component
public class SecondClass implements Serializable {

    @Id
    @JoinColumn(name = "MY_ID", referencedColumnName = "MY_ID")
    @OneToOne
    private FirstClass firstClass;
}

With the Cascade option set then you you will only need to make the call to save firstClass: the associated secondClass will be persisted automatically - assuming you set both sides of the relationhsip in your in-memory model i.e.

firstClass.setSecondClass(secondClass);
secondClass.setFirstClass(firstClass);
Alan Hay
  • 22,665
  • 4
  • 56
  • 110
  • Thank you - this helps me understand the concept better. I'm now facing a `org.hibernate.AnnotationException: Unknown mappedBy in: mypackage.mysubpackage.FirstClass.secondClass, referenced property unknown: mypackage.mysubpackage.SecondClass.firstClass`? Could it be a configuration issue at this point? – abhi Aug 09 '16 at 14:36
  • make sure that classes are properly registered in persistence xml, check that "Entity" annotation is present in both classes. Also I can tell that you're using less complex classes for representation matters of your issue, it would be useful to see the actual classes. – Daniel Arechiga Aug 09 '16 at 20:49
  • Thank you all! It works perfectly now. I pieced what each of you had together and I studied the documentation a bit more and it all makes sense :) @DanielArechiga – abhi Aug 10 '16 at 01:25
1

Add @GeneratedValue(strategy=GenerationType.IDENTITY) to the id of second class.

@Id
@Column(name = "MY_ID")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer myId;
// more variables, getters/setters
Jens
  • 67,715
  • 15
  • 98
  • 113
  • When adding that, I get the following error: `org.hibernate.MappingException: org.hibernate.dialect.identity.IdentityColumnSupportImpl does not support identity key generation` – abhi Aug 08 '16 at 22:02
  • if it helps, my id is not set to auto increment in the table that the second class uses. – abhi Aug 08 '16 at 22:05
  • See here: http://stackoverflow.com/questions/24009042/org-hibernate-dialect-oracledialect-does-not-support-identity-key-generation – Jens Aug 08 '16 at 22:05
1

From your description it seems like you have a ManytoOne relation, as your table B references table A, then it's logic to say A has a list of Bs somewhat, so why not take advantage of what ORM actually is and why not keep a reference in A such as:

@OneToMany(mappedBy="aa")
private List<B> bs;

and use the annotation in the other entity:

@ManyToOne
@JoinColumn(name = "myId" , referencedColumnName = "id")
private A aa;

That in combination to what Jens suggested, see OracleDialect does not support identity key generation

Community
  • 1
  • 1
Daniel Arechiga
  • 847
  • 7
  • 19
  • I added some more background to the question, it would be a one to one relationship since only one id in table A should have a corresponding single id in table B (i.e. ID 100 in table A should have only one ID of 100 in table B) – abhi Aug 08 '16 at 22:35
  • Same applies, just remove the List declaration and do it as single bean attribute, change the oneToMany and ManyToOne to OneToOne respectively – Daniel Arechiga Aug 08 '16 at 22:42
  • Tried to add exactly that but getting a `org.hibernate.AnnotationException: @Column(s) not allowed on a @OneToOne property:` Sorry I've been at this for hours and it's just not clicking with me. I updated my question to reflect the code you and Jens recommended along with any relevant links – abhi Aug 08 '16 at 23:17