2

I have two classes, CalculatedValue and Price. Price has map of CalculatedValue. Each CalculableValue instance has name, value and couple of other fields.

Here is mapping I use to describe a dependency between Price and the CV:

@OneToMany(
        cascade = CascadeType.ALL,
        fetch = FetchType.EAGER
)
@JoinColumn(name = "priceId")
private Map<String, CalculatedValue> calculatedValues =
        new TreeMap<String, CalculatedValue>();

No join table, just mapping by priceId column which refers to Price unique Id.

Here is how generated table looks like:

CREATE TABLE PUBLIC.CALCULATEDVALUE ( UNIQUEID BIGINT NOT NULL, KEY VARCHAR(2147483647) NOT NULL, PRICEID BIGINT, VALUE DOUBLE NOT NULL, CALCULATEDVALUES_KEY VARCHAR(2147483647), PRIMARY KEY (UNIQUEID) );

ALTER TABLE PUBLIC.CALCULATEDVALUE ADD FOREIGN KEY (PRICEID) REFERENCES TEST.PUBLIC.PRICE (UNIQUEID);

Everything is working, but I want to know if it possible to to this:

  1. Avoid automatic "CALCULATEDVALUES_KEY" column creation. I already have this value stored in KEY column and it would be nice to avoid duplication and somehow give a hint to JPA.
  2. Trigger cascade delete of calculable value for each removed price (in case I'm running SQL delete statement)
  3. Will such mapping work in case I'll use Date as a key? Not for this particular field, but for a bunch of other ones it will be useful. Assuming the same OneToMany relationship.

Thank you in advance!

PS. I'm using latest version of EclipseLink & H2 as database. PPS. Didn't want to store the calculable values in array since I need to often find it buy key in Java.

Val
  • 381
  • 1
  • 3
  • 11

1 Answers1

1

For info on Maps see,

http://en.wikibooks.org/wiki/Java_Persistence/OneToMany

and,

http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Maps

and,

http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_cascadeondelete.htm#CIABIIEB

A few issues:

  • EclipseLink will use Hashtable by default for Map, if you want it to use TreeMap you need to define the field as TreeMap.
  • Do not give a @JoinColumn on a @OneToMany, this is only supported for advanced unidirectional @OneToMany, a normal @OneToMany should use a mappedBy and have an inverse @ManyToOne in the target entity. (this will fix your issue of the duplicate foreign key).
  • You need to specify the @MapKey for a map, otherwise it defaults to the id, which seems to be an integer here, not a string.
  • You can use @CascadeOnDelete in EclipseLink to cascade a delete on the database.
James
  • 17,965
  • 11
  • 91
  • 146
  • Thanks for your answers. Here is how I have it described now: Price class: @OneToMany( cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "price" ) private Map calculatedValues = new TreeMap(); CalculatedValue class: @ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name="priceId") private Price price; – Val Dec 11 '12 at 18:53
  • Two problems: 1) priceId column is generated, but not filled automatically. Is there any way to keep it filled automatically? I guess I need something as simple as OneToMany + JoinColumn from my first example having no need to fill back-references manually. 2) I still have CALCULATEDVALUES_KEY column generated automatically. Is there any way to avoid and help JPA understand that I already have a key stored in KEY column? – Val Dec 11 '12 at 18:54
  • Tried to use TreeMap instead of Map and eclipselink generates an error - This mapping's attribute class does not match the collection class. [class java.util.Hashtable] cannot be assigned to [class java.util.TreeMap]. Tried to find info on what eclipselink does support but no luck... Not sure if I want to switch to hibernate.. – Val Dec 12 '12 at 02:56
  • 1
    It appears the EclipseLink just uses Hashtable for any maps regadles of what you have specified when you declared a field. To give it a hint on what is exact collection class I want to use I used DescriptorCustomizer extension point. Code looks like this mapping.useMapClass(TreeMap.class, methodName) – Val Dec 23 '12 at 23:58