openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Tedman Leung <ted...@sfu.ca>
Subject Re: how to store collection of enums as strings
Date Tue, 31 Mar 2009 17:50:38 GMT
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
<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".
>>>>>>>                         
>>>>>>                   
>>>>         
>>
>>   
>

-- 
                                                           Ted Leung
                                                           tedman@sfu.ca

The most important words I've learned to say - "I don't know".

Mime
View raw message