Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Problem with persist order in 3 table scenario including inheritance and OneToMany relationship
Problem with persist order in 3 table scenario including inheritance and OneToMany relationship [message #813913] Mon, 05 March 2012 21:01 Go to next message
Michael Gruebsch is currently offline Michael GruebschFriend
Messages: 16
Registered: March 2012
Junior Member
Hi,

I have a 3-table-scenario running on Postgres 9.1 with EclipseLink 2.3.1

Table A/class A is the super-table/-class of table B/class B; inheritance strategy is joined.

The 3rd table is H which has a foreign key to B. In Java it is a OneToMany-Relationship from B to H (cascade=ALL).

If I create a new instance of Class B and set a relation from B to a new instance of H, then I get errors when EclipseLink persists the entities. EclipseLinks save the table data in that order:


A (because B inherits from A; primary key is defined there)
H
B

That is: H is saved before B. However, because table H references B by a foreign key this is the wrong order: when H is saved there is no corresponding row in B. The transaction fails:
Could not create the view: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.1.v20110908-r10021): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: insert or update on table "h" violates foreign key constraint "fk_h_b"
  Detail: Key (h_id)=(3) is not present in table "b".
Error Code: 0
Call: INSERT INTO H (X, h_id) VALUES (?, ?)
	bind => [1, 3]
Query: InsertObjectQuery(de.viate.gwai.core.dao.entity.test.H@b398da)


Is there any way to influence the persist order? Does anybody have a clue how to get this stuff working?

Below you find the sources. Thank you

Michael


SQL
===
CREATE SEQUENCE A_A_ID_seq INCREMENT 1 START 1;

CREATE TABLE A ( 
  A_ID integer DEFAULT nextval(('A_A_ID_seq'::text)::regclass) NOT NULL,
  TYP char(1) NOT NULL
);

CREATE TABLE B ( 
  B_ID integer NOT NULL
);


CREATE TABLE H ( 
  H_ID integer NOT NULL,
  X integer not null
);

ALTER TABLE A ADD CONSTRAINT PK_A PRIMARY KEY (A_ID);

ALTER TABLE B ADD CONSTRAINT PK_B PRIMARY KEY (B_ID);

ALTER TABLE H ADD CONSTRAINT PK_H PRIMARY KEY (H_ID, X);

ALTER TABLE B ADD CONSTRAINT FK_B_A FOREIGN KEY (B_ID) REFERENCES A (A_ID);

ALTER TABLE H ADD CONSTRAINT FK_H_B FOREIGN KEY (H_ID) REFERENCES B (B_ID);


JAVA
====

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "typ")
public class A implements Serializable
{
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "a_id")
  private Integer aId;

  public A()
  {
  }

  public Integer getAId()
  {
    return this.aId;
  }

  public void setAId(Integer aId)
  {
    this.aId = aId;
  }
}

@Entity
@DiscriminatorValue("B")
@PrimaryKeyJoinColumn(name = "b_id")
public class B extends A implements Serializable
{
  private static final long serialVersionUID = 1L;

  // bi-directional many-to-one association to H
  @OneToMany(mappedBy = "b", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
  private Set<H> hs;

  public B()
  {
  }

  public Set<H> getHs()
  {
    return this.hs;
  }

  public void setHs(Set<H> hs)
  {
    this.hs = hs;
  }

}

@Entity
public class H implements Serializable
{
  private static final long serialVersionUID = 1L;

  @EmbeddedId
  private HPK id;

  // bi-directional many-to-one association to B
  @ManyToOne(optional = false)
  @JoinColumn(name = "h_id")
  private B b;

  public H()
  {
  }

  public HPK getId()
  {
    return this.id;
  }

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

  public B getB()
  {
    return this.b;
  }

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

}
@Embeddable
public class HPK implements Serializable
{
  // default serial version id, required for serializable classes.
  private static final long serialVersionUID = 1L;

  @Column(name = "h_id", insertable=false, updatable=false, nullable=false)
  private Integer hId;

  private Integer x;

  public HPK()
  {
  }

  public Integer getHId()
  {
    return this.hId;
  }

  public void setHId(Integer hId)
  {
    this.hId = hId;
  }

  public Integer getX()
  {
    return this.x;
  }

  public void setX(Integer x)
  {
    this.x = x;
  }

  @Override
  public boolean equals(Object other)
  {
    if (this == other)
    {
      return true;
    }
    if (!(other instanceof HPK))
    {
      return false;
    }
    HPK castOther = (HPK) other;
    return this.hId.equals(castOther.hId) && this.x.equals(castOther.x);

  }

  @Override
  public int hashCode()
  {
    final int prime = 31;
    int hash = 17;
    hash = hash * prime + this.hId.hashCode();
    hash = hash * prime + this.x.hashCode();

    return hash;
  }
}

...

      EntityManager e = ...;
      
      B b = new B();
      H h = new H();
      HPK hpk = new HPK();
      hpk.setX(1);
      h.setId(hpk);
      h.setB(b);
      Set<H> hs = new HashSet<H>();
      hs.add(h);
      b.setHs(hs);
      
      e.persist(b);



Re: Problem with persist order in 3 table scenario including inheritance and OneToMany relationship [message #814517 is a reply to message #813913] Tue, 06 March 2012 14:52 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris DelahuntFriend
Messages: 1039
Registered: July 2009
Senior Member
If you remove the 'orphanRemoval = true' tag from the OneToMany, does it work? The problem might be that the relationship from H is to the A table's a_id since that is the primary key, so the constraint on the database does not match what was mapped. I believe you can fix this by specifying that the join column reference the B table b_id field, though it might not be portable since it is not the primary key.

Best Regards,
Chris
Re: Problem with persist order in 3 table scenario including inheritance and OneToMany relationship [message #815570 is a reply to message #814517] Wed, 07 March 2012 20:37 Go to previous messageGo to next message
Michael Gruebsch is currently offline Michael GruebschFriend
Messages: 16
Registered: March 2012
Junior Member
Chris, thanks for your help!

I'm sorry: removing 'orphanRemoval = true' didn't help.

What's wrong with the mapping?

The intention is to let B be a subclass of A. It has the same primary key. Only B has a relationship to H. Each B may have multiple H's.

Thank you
Michael
Re: Problem with persist order in 3 table scenario including inheritance and OneToMany relationship [message #816355 is a reply to message #815570] Thu, 08 March 2012 18:55 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris DelahuntFriend
Messages: 1039
Registered: July 2009
Senior Member
The problem is that you have defined the database relationship differently than the object model. JPA forces the H->B reference to use B's primary key, which happens to be TableA's A_ID. EclipseLink respects the constraints it knows about, but doesn't know that H really has a constraint to the Btable B_ID, and so allows the H insert before the insert to B.

If changing the relationship join column doesn't work, you can set setHasMultipleTableConstraintDependecy on the descriptor that will prevent the BTable inserts/updates from being deferred. This would need to be done through a descriptor customizer or session customizer described here:
http://wiki.eclipse.org/Customizing_the_EclipseLink_Application_(ELUG)

Best Regards,
Chris
Re: Problem with persist order in 3 table scenario including inheritance and OneToMany relationship [message #816401 is a reply to message #816355] Thu, 08 March 2012 20:21 Go to previous message
Michael Gruebsch is currently offline Michael GruebschFriend
Messages: 16
Registered: March 2012
Junior Member
Thanks again, Chris, for your help.

One more question. The data modell has the constraint

ALTER TABLE H ADD CONSTRAINT FK_H_B FOREIGN KEY (H_ID) REFERENCES B (B_ID);


This is the primary key of B:

ALTER TABLE B ADD CONSTRAINT PK_B PRIMARY KEY (B_ID);


Is it this what you mean by
Quote:

JPA forces the H->B reference to use B's primary key

? Unfortunatly I do not understand where the data model and the object model differ.

You said, that the primary key of B is identical to that of table A. Is this the viewpoint of EclipseLink which processes the relation as "inheritance" not as "one-to-one"? From the viewpoint of the database both has the same value as any foreign-primary-key-pair, but they are not the same, I think?

Suppose we drop both the constraint from B to A as well as the table A: Do the object model and the data model match now? Does EclipseLink insert B at first and H afterwards? If yes why doesn't happen this when A is present?

Thanks for your patience!
Michael
Previous Topic:MOXy - specify element form in external bindings
Next Topic:EclipseLink 2 on Tomcat
Goto Forum:
  


Current Time: Mon Nov 24 01:33:26 GMT 2014

Powered by FUDForum. Page generated in 0.02298 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software