Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java EE 6 JPA 2 ManyToOne Relation Creates Invalid Foreign Key

I am trying to create two entities where both entities have embeddedIds. One of the entities have 2 references to the other entity, where both of those references are related as ManyToOne.

Example codes are written below;

@Embeddable
public class ItemPK {
  @Column(nullable = false, length = 100)
  private String itemId;
  @Column(name = "item_client_id", nullable = false)
  private int clientId; 
  ...
}

@Entity
@Table(name = "item")
public class Item {
  @EmbeddedId
  private ItemPK id;

  @ManyToOne
  @JoinColumn(name = "item_client_id")
  private Client client;

  @OneToMany(mappedBy="item", cascade = CascadeType.ALL, orphanRemoval = true)
  private Set<RelatedItem> relatedItems;

  @OneToMany(mappedBy="relatedItem", cascade = CascadeType.ALL, orphanRemoval = true)
  private Set<RelatedItem> relatedItemsRHS;
  ...
}

@Embeddable
public class RelatedItemPK {
  @Column(name = "itemId", length = 100, nullable = false)
  private String itemId;
  @Column(name = "item_client_id", nullable = false)
  private int clientId;
  @Column(name = "relatedItemId", length = 100, nullable = false)
  private String relatedItemId;
  @Column(name = "related_item_client_id", nullable = false)
  private int relatedItemClientId;
  ...
}

@Entity
@Table(name = "related_item")
public class RelatedItem {
  @EmbeddedId
  private RelatedItemPK id;

  @ManyToOne(cascade = CascadeType.ALL, optional = false)
  @JoinColumns({
    @JoinColumn(name="itemId", referencedColumnName="itemId", insertable=false, updatable=false),
    @JoinColumn(name="item_client_id", referencedColumnName="item_client_id", insertable=false, updatable=false)
  })
  private Item item;
  @ManyToOne(cascade = CascadeType.ALL, optional = false)
  @JoinColumns({
    @JoinColumn(name="related_item_client_id", referencedColumnName="item_client_id", insertable=false, updatable=false),
    @JoinColumn(name="relatedItemId", referencedColumnName="itemId", insertable=false, updatable=false)
  })
  private Item relatedItem;
  ...
}

The problem is while creating foreign keys for RelatedItem entity, I got an SQLException. It is the second ManyToOne relation that fails. The foreign key generation sql is below,

ALTER TABLE related_item ADD CONSTRAINT FK_related_item_related_item_client_id FOREIGN KEY (related_item_client_id, relatedItemId) REFERENCES item (item_client_id, itemId)

Since item table is indexed first by itemId then by item_client_id, this statement causes MySQL to produce an error.

I would like to switch the places of columns so that the SQL should look like the following,

ALTER TABLE related_item ADD CONSTRAINT FK_related_item_relatedItemId FOREIGN KEY (relatedItemId, related_item_client_id) REFERENCES item (itemId,item_client_id)

I tried changing the order of "JoinColumn"s but the result didn't change. I also tried renaming the fields to check if persistence provider choses the order by column name but again the result didn't change.

So, is there a way to enforce the column ordering?

p.s. I use following stuff:

  • MySQL 5.1
  • EclipseLink 2.0.0
  • Java EE 6
  • JPA 2
  • GlassFish v3

Edit: EclipseLink produces following SQL, which fails to run;

CREATE TABLE related_item (SIMILARITY DOUBLE, widget_id INTEGER NOT NULL, relatedItemId VARCHAR(100) NOT NULL, itemId VARCHAR(100) NOT NULL, related_item_client_id INTEGER NOT NULL, item_client_id INTEGER NOT NULL, PRIMARY KEY (widget_id, relatedItemId, itemId, related_item_client_id, item_client_id));
CREATE TABLE item (IMAGEURL VARCHAR(2048), STATUS VARCHAR(64), URL VARCHAR(2048), PRICE DOUBLE, STOCK INTEGER, DESCRIPTION TEXT(64000), NAME VARCHAR(255), ITEMID VARCHAR(100) NOT NULL, item_client_id INTEGER NOT NULL, PRIMARY KEY (ITEMID, item_client_id));
ALTER TABLE related_item ADD CONSTRAINT FK_related_item_itemId FOREIGN KEY (itemId, item_client_id) REFERENCES item (itemId, item_client_id);
ALTER TABLE related_item ADD CONSTRAINT FK_related_item_related_item_client_id FOREIGN KEY (related_item_client_id, relatedItemId) REFERENCES item (item_client_id, itemId);
ALTER TABLE item ADD CONSTRAINT FK_item_item_client_id FOREIGN KEY (item_client_id) REFERENCES client (ID);
like image 944
bdaylik Avatar asked Nov 15 '22 04:11

bdaylik


1 Answers

Please include the stack trace. However, I strongly recommend you skip the @JoinColumn tags unless you have a VERY good reason for specifying the foreign keys yourself. By specifying the mappedBy attribute in one of the directions, JPA can figure out what to do by itself.

Java EE 6 and JPA put a lot of effort into enabling Convention over Configuration, which means that most of the time, things will work out of the box. It's desirable for you, the programmer because you have less boiler plate code to worry about, and it's desirable for the JPA and Jave EE container implementors because it gives them freedom to chose the best performing solutions. By declaring the foreign key relationships yourself, you rob both you and JPA of this advantage.

Edit: In fact, I suspect that both specifying mappedBy and specifying the @JoinTable could be the root cause of your problem. But I need to see the stack trace to tell for sure.

like image 108
Kim Burgaard Avatar answered Apr 25 '23 03:04

Kim Burgaard