We suggest a change in how OpenJPA determines the names to be used for DB columns when using value handlers that use multiple columns. When a @Column annotation (or the equivalent in XML) is found for a property or field that is handled by a value handler, the name passed to the map() method should be the name in the annotation, and not the name of the property or field.



While working with ValueHandlers that use multiple columns, we found the following behavior (using OpenJPA on WebSphere 6.1..., thus OpenJPA 1.0.3. (?)):

For a developer of an entity that uses the complex value type for which we write the value handler, the complex value type is "one thing". She doesn't (want to) know the internal complexity. The goal of complex value types is indeed encapsulation. The developer of the entity also does not (want to) know on how many and which columns we want to persist.

The name given as parameter in the map() function of a ValueHandler is the name of the underlying property / field. It is the intention to define names on the Columns we return that are distinct for the different columns, in the context of any use (i.e., for many different properties that use our complex value type, in many different entities, by many different developers). Therefor it is not a bad idea to name the columns something like <code>name + "_subcolumndescription"</code>.

E.g., we have a TimeInterval complex value type, that features a begin and end property. We want, in particular circumstance, to persist time intervals in 2 TIMESTAMP columns, called <code>name + "_begin"</code> and <code>name + "_end"</code>. When applied to a property / field called "subscriptionPeriod", you thus get in the database the columns "SUBSCRIPTIONPERIOD_BEGIN" and "SUBSCRIPTIONPERIOD_END".

So far, so good.

Now, for several good reasons, developers might want to override the (base) name used for column names. We don't want to use the name of the field / property, but something else (particularly handy when your style uses a prefix for instance variables like "$" or "_"). This is supported in JPA with the @Column() annotation.

Now, we observe that when we combine this annotation with the OpenJPA value handlers, that we get an error, because we have only defined 1 column name, and we need n for our property. The solution is to use the OpenJPA @Columns({}) annotation, where we can nest a @Column() annotation with a specific name for each column.

In our example, suppose we want to use "SUBSRC" as column name:

@Column("SUBSCR") gives an error

and

@Columns([EMAIL PROTECTED]("SUBSCR_BEGIN"), @Column("SUBSCR_END")}) gives indeed 2 columns with those names in the database. The naming is then dependent on the order.

We suggest that this breaks encapsulation. To make this work, the developer indeed needs to be aware of the internal of TimeIntervalValueHandler.





We suggest a small change in OpenJPA: when calling the map() method, give as name the name of the property / field if no @Column() annotation is found, or if the @Columns() annotation is found (although then it is irrelevant, but passing null is not a backward compatible option). This is the current behavior. In the case the @Column() annotation (or the equivalent in XML) is found however, pass in the name given in the annotation as name parameter to the map() method, instead of the current property / field name. Also, the verification would have to be changed to not throw an error in this case.





The behavior with @Columns() should be kept as fallback for legacy databases (although in that case you probably will not be working with complex value types and value handlers?).





Reply via email to