Question

I have an entity, Item, that is related to other Items through a join table. However, I need to insert the value of "additionalField" when persisting a related item.

I am using spring data JPA (1.4.1) for my persistence abstraction. EclipseLink (2.5.0) is my JPA provider.

@Entity
public class Item {

   // other fields and getters/setters omitted for clarity

   @OneToMany
   @JoinTable(name = "related_items_map", 
         joinColumns = @JoinColumn(name = "fk_item"),
         inverseJoinColumns = @JoinColumn(name = "fk_related_item"))
   private List<Item> relatedItems;   
}

join table name = "related_items_map" with 
    columns = fk_item, fk_related_item, additionalField

My end goal is to achieve the following semantics:

// obtain the items from service by id
Item item = itemService.findOne(1);
Item relatedItem = itemService.findOne(2);

// add related item to item related list
item.getRelatedItems().add(relatedItem);

// save item using service
itemService.save(item);

Today the generated SQL looks correct

INSERT INTO item (fk_item, fk_related_item) values (?, ?) => bind [1, 2]

The only issue is that additionalField column is null. The value that should be inserted is to be calculated (based upon certain state) at run time prior to the insert.

How do I customize the insert for this operation? I know how to customize specific classes, but not mappings.

==== UPDATE ====

As suggested by Chris, I created an entity wrapping the "JoinTable"

@Entity
@Table("related_items_map")
public class RelatedItem {
   @Id
   private String itemId;

   @Id
   private String relatedItemId;

   // ... other stuff
}

@Entity
public class Item {

   // other fields and getters/setters omitted for clarity

   @OneToMany
   @JoinTable(name = "related_items_map", 
         joinColumns = @JoinColumn(name = "fk_item"))
   private List<RelatedItem> relatedItems;   
}

However, eclipselink is attempting to do a multiple insert now when I do the following:

// obtain two items
Item item = itemService.find(1);
Item other = itemService.find(2);

// create the joining
RelatedItem relatedItem = new RelatedItem();
relatedItem.setItemId(item.getId());
relatedItem.setRelatedId(other.getId());

// add the relation to the list of relations
item.getRelatedItems().add(relatedItem);

// update the item.
itemService.save(item);

I am getting a key constraint violation because it is attempting to do two inserts:

INSERT INTO related_items_map(fk_item, fk_related_item, ...) values (?, ?, ...) => bind [1, 2, ...]

INSERT INTO related_items_map(fk_item, fk_related_item) values (?, ?) => bind [1 ,2]

The first insert I am assuming because it is creating the actual entity. The second I am assuming is because of the OneToMany relationship on the Item class. How do I omit that second insert?

Was it helpful?

Solution

Unless that field is an index of some sort, or you wanted to use a map and have that field used as the key or value, JPA only allows for fields to be mapped within entities.

So to be portable without having to get into provider specifics, you would need to create an entity for that relation table. This allows the field to be used in queries and accessed like any other field.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top