[hibernate-issues] [Hibernate-JIRA] Commented: (ANN-472) @UniqueConstraint declaration is not friendly towards inheritance or reflection

Ted Bergeron (JIRA) noreply at atlassian.com
Tue Oct 24 20:50:05 EDT 2006


    [ http://opensource.atlassian.com/projects/hibernate/browse/ANN-472?page=comments#action_24977 ] 

Ted Bergeron commented on ANN-472:
----------------------------------

API Extension:

getInvalidValues could accept the bean and use Java 5's varargs ability to allow for one or more String propertyNames:    public InvalidValue[] getInvalidValues(T bean,  String... propertyNames)
getPotentialInvalidValues would have to accept a Map:    public InvalidValue[] getPotentialInvalidValues(Map<String, Object> propertyValueMap)


Now you've got me thinking about the details of doing this exactly right.  The validations need to honor priorities.  IE, if instead of name, I am putting unique constraints on an email property, I'd best make sure the user input passes basic validation first.  No sense in hitting the database looking to see if invalid data would violate a unique constraint.

My ideal solution is not possible currently, thanks to Java 5's limitations around inheritance and annotation overriding.  I'll list the code below in the hopes it gives you an idea, or that java 6/7 makes this possible:

in NameableObject

...

@Column(name = "name")
@Length(min = 1, max = NAME_LENGTH)
@NotNull
public String getName() {
    return name;
}

in LookupObject extends NameableObject

...

@Override
@Column(name = "name", unique = true)    //  We add a unique constraint for lookupObjects
@Length(min = 1, max = NAME_LENGTH)
@NotNull
public String getName() {
    return super.getName();
}

in CustomerBoundLookupObject extends LookupObject

...

@Override
@Unique(composite = true, constraintname = "cust_name")
@Column(name = "name")
@Length(min = 1, max = NAME_LENGTH)
@NotNull
public String getName() {
    return super.getName();
}

@Unique(composite = true, constraintname = "cust_name")
@NotNull
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
@JoinColumn(name = "cust_id")
public Customer getCustomer() {
    return customer;
}

The idea here is that I can query a property via reflection and ask if it needs to be unique, or participates in one or more composite unique constraints.  If I find one or more composite constraints, I can iterate over the bean's properties looking for the other properties that belong to the constraint.  On finding the 2+ properties, I could generate a select statement with the 2+ columns in the where clause to test if a transient bean would violate my constraint.  If the validator would automatically generate the selects when validating, but only if the simple validations all pass, that would be perfect.

At the bean level, we could optionally define the constraint much like:  @SequenceGenerator  We'd give it the meaningless name to match with the @Unique annotation, and the real database name of the constraint. 

Without the inheritance that is impossible, this would still be useful as is.  If you do not agree with any of the above, then at the very least, changing:

uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})} 

to use property names vs column names would help with the reflection.  (And hibernate can easily derive column names from properties.)




> @UniqueConstraint declaration is not friendly towards inheritance or reflection
> -------------------------------------------------------------------------------
>
>          Key: ANN-472
>          URL: http://opensource.atlassian.com/projects/hibernate/browse/ANN-472
>      Project: Hibernate Annotations
>         Type: Improvement

>     Versions: 3.2.0.ga
>  Environment: Hibernate 3.2 GA
>     Reporter: Ted Bergeron

>
>
> The current way to define a composite unique constraint is limiting.
> @Table(name="tbl_sky",
>     uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})}
> )
> Suppose I have an abstract base class called A that gives me Id and Name, subclassed by abstract class B that gives me Customer.  Then I have many concrete classes that subclass B.  For all of these, I'd want the combination of Name and Customer to be unique.  As I do not use @Table with abstract base classes, I currently have to repeat:  uniqueConstraints = {@UniqueConstraint(columnNames={"name", "customer_id"})}  on all concrete classes.  
> If we had an alternate way to define these constraints at the property level (as XDoclet did with hibernate 2), I could define this in the base classes and inherit the constraint declaration.
> The other need is that I would like to use reflection to scan the properties and apply proper validations in the view layer.  With @Column(unique = true) this is easy to do.  The view layer makes an AJAX call and all is well.  For a composite constraint, it does not work well currently.

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira




More information about the hibernate-issues mailing list