actually no, it's not the simplest way.
The example I provided already works in openJpa with enums or strings,
it's only 1 line of code / 1 annotation
@PersistentCollection
given that annotation, it will already sort out everything you've
mentioned.
@PersistentCollection
private HashSet<String> myStrings=new HashSet<String>();
or
@PersistentCollection
private HashSet<MyEnum> myEnums=new HashSet<MyEnum>();
already creates a second table, a join, and already loads and persists the
2 items for you when the entity is persisted. It works great for the most
part and is really as easy as the above code. (The one exception being
another email I sent saying eager fetching seems to be broken.)
All I really wanted (and also see Craigs posting today) is to allow the
@Enumerated annotation to be allowed and used in addition to the above,
i.e.
@Enumerated(STRING)
@PersistentCollection
private HashSet<MyEnum> myEnums=new HashSet<MyEnum>();
The difference is I'm not persisting another entity, I'm persisting a
primitive or in my case a Enum which I'm considering an instance of the
Enum primitive. The concept extends to peristing other primitives like
java.util.Date too which probably works out of the box right now with
@PersistenCollection but also probably (I haven't tried it) doesn't allow
@Temporal to be annotated at the same time either.
So, to go from having just 2 of code which works but stores the ordinal
value, to having the entire setup you've describe - just to change the
persisted type from ordinal to string, seems like a seriously large work
around especially considering changing an ordinal to string for a single
enum is only 1 extra line too, @Enumerated(STRING).
On Tue, Mar 31, 2009 at 08:23:52AM -0700, Paul Copeland wrote:
> Hi Ted -
>
> Interesting point of view. I would have thought this is the plain
> vanilla "simple clean out of the box" way to persist a Collection of
> Enums or any other kind of collection.
>
> This results in a bare minimum join with two tables and a foreign key
> which is how a Collection maps into the world of relational databases
> whether you are using straight JDBC or JPA or Hibernate or brand X ORM.
> In the end you wind up with two database tables and two objects that
> model the association.
>
> - Paul
>
> On 3/31/2009 7:40 AM, Tedman Leung wrote:
>> thanks but I was hoping there was a simple clean out of the box style
>> solution. Considering the code could/should have just been a single
>> annotation to the collection, the work around looks like an awful lot
>> of work for a framework which is suppose to reduce work.
>>
>> In the end, I just used raw JDBC in a nativeQuery. At least this way
>> other developers can understand the code I've written and it's only
>> actually about 15 lines of simple straight forward code.
>>
>> thanks.
>>
>>
>> On Mon, Mar 30, 2009 at 11:16:52AM -0700, Paul Copeland wrote:
>>
>>> Hi Ted - See example code below
>>>
>>> On 3/30/2009 9:47 AM, Tedman Leung wrote:
>>>
>>>>> Isn't the same thing true that OneToMany should annotate a
>>>>> Collection of Entities? So the Enums would be a field on the
>>>>> ManyToOne side of that kind of mapping. Then you can specify
>>>>> the @Column and @Enumerated annotations on the actual field or
>>>>> property.
>>>>>
>>>> no you can't, I tried it. I can't remember the specific error but
>>>> it was along the lines of - you're not allowed to specify a column
>>>> attribute here.
>>>>
>>> Here is an example that uses the @Enumerated and @Column annotations
>>> on a OneToMany relation.
>>>
>>> This stores a Set of Enums as String values. A similar example would
>>> work for ManyToMany. The same approach can also be used with
>>> Collections of Temporal values.
>>>
>>> There are two classes - an EnumHolder that holds the Collection and
>>> an EnumValue that holds an Enum and stores it as a String. Here is
>>> the MappingTool generated SQL (Postgres database). As you can see
>>> the Enum is stored as a String VARCHAR(10).
>>>
>>> CREATE TABLE enum_holder (id BIGSERIAL NOT NULL, PRIMARY KEY (id));
>>>
>>> CREATE TABLE enum_value (id BIGSERIAL NOT NULL, StringEnum
>>> VARCHAR(10), ENUMHOLDER_ID BIGINT, PRIMARY KEY (id));
>>>
>>> package com.jpa.test;
>>>
>>> import javax.persistence.*;
>>> import java.util.*;
>>>
>>> @Entity
>>> @Table (name="enum_holder")
>>> public class EnumHolder
>>> implements java.io.Serializable
>>> {
>>> @GeneratedValue(strategy=GenerationType.IDENTITY)
>>> @Id private long id;
>>>
>>> @OrderBy
>>> @OneToMany(mappedBy="enumHolder", fetch=FetchType.LAZY,
>>> cascade={CascadeType.PERSIST,CascadeType.REMOVE})
>>> private Set<EnumValue> enums;
>>>
>>> public Set<EnumValue> getEnums()
>>> {
>>> if (enums == null)
>>> enums = new HashSet<EnumValue>();
>>> return enums;
>>> }
>>> }
>>>
>>> package com.jpa.test;
>>>
>>> import javax.persistence.*;
>>>
>>> @Entity
>>> @Table (name="enum_value")
>>> public class EnumValue
>>> implements java.io.Serializable
>>> {
>>> public static enum MyEnum{foo, Bar, Batz, woohoo}
>>>
>>> @GeneratedValue(strategy=GenerationType.IDENTITY)
>>> @Id private long id;
>>>
>>> @ManyToOne (optional=false, fetch=FetchType.LAZY,
>>> cascade=CascadeType.PERSIST)
>>> private EnumHolder enumHolder;
>>>
>>> @Enumerated (EnumType.STRING)
>>> @Column(name="StringEnum", length=10)
>>> private MyEnum myEnum;
>>>
>>> public MyEnum getMyEnum() { return myEnum; }
>>> }
>>>
>>>
>>>
>>> On 3/30/2009 9:47 AM, Tedman Leung wrote:
>>>
>>>>> How does your original example of ManyToMany annotation on a
>>>>> Collection of Enums actually work? My understanding is that for
>>>>> ManyToMany both sides must be persistent Entities. So therefore
>>>>> the ManyToMany is mapping the join table, not the Enum.
>>>>>
>>>> yes oddly enough it actually does work. As per my subsequent email,
>>>> I switched it to @PersistentCollection and it performed the same
>>>> way. I considered trying to annotate my Enum like an Entity but I
>>>> figured that would be pushing expected behaviour... even if it
>>>> worked, so I decided not to.
>>>>
>>>>
>>>>
>>>>> Isn't the same thing true that OneToMany should annotate a
>>>>> Collection of Entities? So the Enums would be a field on the
>>>>> ManyToOne side of that kind of mapping. Then you can specify
>>>>> the @Column and @Enumerated annotations on the actual field or
>>>>> property.
>>>>>
>>>> no you can't, I tried it. I can't remember the specific error but
>>>> it was along the lines of - you're not allowed to specify a column
>>>> attribute here.
>>>>
>>>>
>>>>> Could you explain why using the @PersistentCollection annotation
>>>>> is useful or necessary for OneToMany or ManyToMany collections
>>>>> generally or specifically in the case you are looking at? I
>>>>> don't understand the use case that @PersistentCollection
>>>>> satisfies.
>>>>>
>>>> My understanding is @ManyToMany is a JPA standard and is only used
>>>> to map entity to entities.
>>>>
>>>> My understanding of @PersistentCollection is that is is an OpenJpa
>>>> extention which allows people to map Entity to java Primities.
>>>>
>>>> i.e.
>>>>
>>>> @Entity
>>>> class Bar
>>>> {
>>>> }
>>>>
>>>> @Entity
>>>> class Foo
>>>> {
>>>> @ManyToMany
>>>> HashSet<Bar> myBars=new HashSet<Bar>();
>>>>
>>>> @PersistentCollection
>>>> HashSet<String> myStrings=new HashSet<String>();
>>>> }
>>>>
>>>>
>>>> I guess there's a reason why the original JPA standard left out
>>>> primitives... it gets complicated fast.
>>>>
>>>>
>>>>
>>>>> - Paul
>>>>>
>>>>>
>>>>> On 3/29/2009 8:43 PM, Tedman Leung wrote:
>>>>>
>>>>>> Just to document more thoughts and findings.
>>>>>>
>>>>>> 1) I was using the wrong annotation, I should have been using
>>>>>> @PersistentCollection
>>>>>>
>>>>>> 2) this seems to be a more wide spread problem with defining
>>>>>> attributes to collections, i.e. - collection of enums needs to
>>>>>> have @Enumerated configurations
>>>>>> - collection of Dates needs to have @Temporal configurations
>>>>>> - even collection of Strings seems to be missing a
>>>>>> @Column(nullable=false, length=32) style annotation.
>>>>>>
>>>>>> I think the problem is much bigger and wide spread than I originaly
>>>>>> though,
>>>>>> I don't think I'll be able to sort out a patch.
>>>>>>
>>>>>>
>>>>>> On Sun, Mar 29, 2009 at 07:55:06AM -0700, Tedman Leung wrote:
>>>>>>
>>>>>>> yes I know I can do manual hacks to get them stored the way I
>>>>>>> want to, but I was asking if there was a jpa / openjpa
>>>>>>> annotation to allow that.
>>>>>>>
>>>>>>> As an example, I can just use @Enumerated on a single enum,
>>>>>>> so it seems logical that some one would have thought about
>>>>>>> storing a collection of enums.
>>>>>>>
>>>>>>> As for why I want them as strings instead of ordinals - the
>>>>>>> usual reasons, i.e. it's safer for changes as the ordering
>>>>>>> won't accidentally corrupt my data (and without telling me),
>>>>>>> and it's easier to look into the database via sql or
>>>>>>> something and just know what's going on / get simple reports
>>>>>>> etc.
>>>>>>>
>>>>>>> I'm guessing right now that it's not possible at all and that
>>>>>>> no one has done anything towards this. I might have to
>>>>>>> rummage through the source and try to see if I can figure out
>>>>>>> how it works and hack a patch to submit. It seemed like a
>>>>>>> very straight forward use case though so I'm surprised no one
>>>>>>> has asked or done anything about this before.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Sat, Mar 28, 2009 at 10:13:16PM -0700, Paul Copeland wrote:
>>>>>>>
>>>>>>>> What is your objective? Do you want some non-JPA
>>>>>>>> application to see them in the database as Strings?
>>>>>>>>
>>>>>>>> At some point you have add these Enums to the collection
>>>>>>>> one at a time. You can use an addEnum() method or an
>>>>>>>> Entity listener to convert them to Strings at that point
>>>>>>>> one at a time. And a subclass of the Collection type to
>>>>>>>> getEnum() from the Collection when you fetch them back.
>>>>>>>>
>>>>>>>> new MyStringEnumHashSet<MyStringEnumType>()
>>>>>>>>
>>>>>>>> On 3/28/2009 9:27 PM, Tedman Leung wrote:
>>>>>>>>
>>>>>>>>> No, I'm talking about when the enum is in a collection.
>>>>>>>>>
>>>>>>>>> i.e.
>>>>>>>>>
>>>>>>>>> Private HashSet<Gender> genders=new HashSet<Gender>();
>>>>>>>>>
>>>>>>>>> So no, either the @Enumerated helps, nor does calling
>>>>>>>>> name() or toString as neither are possible.
>>>>>>>>>
>>>>>>>>> I'm storing a Collection of enums , not a single Enum.
>>>>>>>>>
>>>>>>>>> There seems to be no examples of this nor any
>>>>>>>>> documentation about the ability to do this that I can
>>>>>>>>> find. The default seems to use the ordinal value both for
>>>>>>>>> table generation and storage value.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Sat, Mar 28, 2009 at 01:56:13PM -0700, Paul Copeland wrote:
>>>>>>>>>
>>>>>>>>>> Hi - This is from the OpenJPA relations example -
>>>>>>>>>>
>>>>>>>>>> @Basic @Enumerated(EnumType.STRING)
>>>>>>>>>> private Gender gender;
>>>>>>>>>>
>>>>>>>>>> public static enum Gender { MALE, FEMALE }
>>>>>>>>>>
>>>>>>>>>> public void setGender(Gender gender) {
>>>>>>>>>> this.gender = gender;
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> See section 12.8.1.2 in the OpenJPA Overview
>>>>>>>>>>
>>>>>>>>>> - Paul
>>>>>>>>>>
>>>>>>>>>> On 3/28/2009 1:33 PM, catalina wei wrote:
>>>>>>>>>>
>>>>>>>>>>> Ted,
>>>>>>>>>>> If you are using Java 5, then you could use name() or toString()
>>>>>>>>>>> API on the
>>>>>>>>>>> Enum to get the name of the enum constant in String value.
>>>>>>>>>>>
>>>>>>>>>>> Catalina
>>>>>>>>>>>
>>>>>>>>>>> On Wed, Mar 25, 2009 at 9:48 AM, Tedman Leung <[email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>> Anyone know how to store a collection of enums as Strings instead
>>>>>>>>>>>> of their
>>>>>>>>>>>> ordinal values? (preferably with annotations...)
>>>>>>>>>>>>
>>>>>>>>>>>> i.e.
>>>>>>>>>>>> @ManyToMany
>>>>>>>>>>>> private Set<MyEnum> myEnums=new HashSet<MyEnum>();
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> --
>>>>>>>>>>>> Ted Leung
>>>>>>>>>>>>
>>>>>>>>>>>> [email protected]
>>>>>>>>>>>>
>>>>>>>>>>>> It's time for a new bike when the bulb in your shift light burns
>>>>>>>>>>>> out.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>
>>>>>>> --
>>>>>>> Ted Leung
>>>>>>> [email protected]
>>>>>>>
>>>>>>> The most important words I've learned to say - "I don't know".
>>>>>>>
>>>>>>
>>>>
>>
>>
>
--
Ted Leung
[email protected]
The most important words I've learned to say - "I don't know".