openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Paul Copeland <t...@jotobjects.com>
Subject Re: how to store collection of enums as strings
Date Tue, 31 Mar 2009 15:23:52 GMT
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 <tedman@sfu.ca>
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
>>>>>>>>>>>                                             
             tedman@sfu.ca
>>>>>>>>>>>
>>>>>>>>>>> It's time for a new bike when the bulb in your
shift light burns out.
>>>>>>>>>>>
>>>>>>>>>>>                                             
>>>>>>>>>>>                       
>>>>>>>>>>                                     
>>>>>>>>>>                     
>>>>>>>>                       
>>>>>>>>                 
>>>>>> -- 
>>>>>>                                                            Ted Leung
>>>>>>                                                            tedman@sfu.ca
>>>>>>
>>>>>> The most important words I've learned to say - "I don't know".
>>>>>>             
>>>>>>             
>>>>>         
>>>>>           
>>>   
>>>       
>
>   


Mime
View raw message