What properties does #Column columnDefinition make redundant? - java

I often specify my #Column annotations like this:
#Column(columnDefinition="character varying (100) not null",length=100,nullable=false)
As you can see I specify length and nullable even though the columnDefinition already specifies those. That's because I don't know where/when these values are used exactly.
So, when specifying columnDefinition, what other properties of #Column are made redundant?
If it matters, I use Hibernate and PostgreSQL

My Answer: All of the following should be overridden (i.e. describe them all within columndefinition, if appropriate):
length
precision
scale
nullable
unique
i.e. the column DDL will consist of: name + columndefinition and nothing else.
Rationale follows.
Annotation containing the word "Column" or "Table" is purely physical - properties only used to control DDL/DML against database.
Other annotation purely logical - properties used in-memory in java to control JPA processing.
That's why sometimes it appears the optionality/nullability is set twice - once via #Basic(...,optional=true) and once via #Column(...,nullable=true). Former says attribute/association can be null in the JPA object model (in-memory), at flush time; latter says DB column can be null. Usually you'd want them set the same - but not always, depending on how the DB tables are setup and reused.
In your example, length and nullable properties are overridden and redundant.
So, when specifying columnDefinition, what other properties of #Column are made redundant?
In JPA Spec & javadoc:
columnDefinition definition:
The SQL fragment that is used when generating the DDL for the column.
columnDefinition default:
Generated SQL to create a column of the inferred type.
The following examples are provided:
#Column(name="DESC", columnDefinition="CLOB NOT NULL", table="EMP_DETAIL")
#Column(name="EMP_PIC", columnDefinition="BLOB NOT NULL")
And, err..., that's it really. :-$ ?!
Does columnDefinition override other properties provided in the same annotation?
The javadoc and JPA spec don't explicity address this - spec's not giving great protection. To be 100% sure, test with your chosen implementation.
The following can be safely implied from examples provided in the JPA spec
name & table can be used in conjunction with columnDefinition, neither are overridden
nullable is overridden/made redundant by columnDefinition
The following can be fairly safely implied from the "logic of the situation" (did I just say that?? :-P ):
length, precision, scale are overridden/made redundant by the columnDefinition - they are integral to the type
insertable and updateable are provided separately and never included in columnDefinition, because they control SQL generation in-memory, before it is emmitted to the database.
That leaves just the "unique" property. It's similar to nullable - extends/qualifies the type definition, so should be treated integral to type definition. i.e. should be overridden.
Test My Answer
For columns "A" & "B", respectively:
#Column(name="...", table="...", insertable=true, updateable=false,
columndefinition="NUMBER(5,2) NOT NULL UNIQUE"
#Column(name="...", table="...", insertable=false, updateable=true,
columndefinition="NVARCHAR2(100) NULL"
confirm generated table has correct type/nullability/uniqueness
optionally, do JPA insert & update: former should include column A, latter column B

columnDefinition will override the sql DDL generated by hibernate for this particular column, it is non portable and depends on what database you are using. You can use it to specify nullable, length, precision, scale... ect.

Related

Is there Optional in Hibernate

I'm wondering why there is no optional (not necessary from Java 8) in Hibernate? It looks like good way to implement lazy OneToOne relation. Instead hibernate suggest to enable byte-code manipulation to achieve lazy one to one.
There is an 'optional' parameter.
#Basic(optional = true) above the column.
"Defines whether the value of the field or property may be null. This is a hint and is disregarded for primitive types; it may be used in schema generation. If not specified, defaults to true."
source: https://www.objectdb.com/api/java/jpa/Basic/optional

#OneToOne(optional=false) and #JoinColumn(nullable=false) used together

I've bumped into this example in JPA 2.0 FR Specification, 11.1.37. OneToOne Annotation, page 403:
#OneToOne(optional=false)
#JoinColumn(name="CUSTREC_ID", unique=true, nullable=false, updatable=false)
public CustomerRecord getCustomerRecord() { return customerRecord; }
Is there any reason that I should put #OneToOne(optional=false) and at that same time put #JoinColumn(... nullable=false)?
Aren't these two declarations the same? Isn't one of them redundant?
Are both of them used in DDL schema generation?
Formally optional=false is a runtime instruction to the JPA implementation, and nullable=false is an instruction to the DDL generator. So they are not strictly redundant.
The difference can become significant when there is entity inheritance involved. If a particular mapping exists only on a subclass, and you have single table table per-hierarchy strategy, then the OneToOne mapping may be optional=false on the particular subclass that contains the mapping. However, the actual join column cannot be made not-null, since then other sub classes that share the table can't be inserted!
In practice different versions of different providers may or may not interpret either one at either time, caveat emptor.

#Basic(optional = false) vs #Column(nullable = false) in JPA

What's the difference between #Basic(optional = false) and #Column(nullable = false) in JPA persistence?
Gordon Yorke (EclipseLink Architecture Committee Member, TopLink Core Technical Lead, JPA 2.0 Expert Group Member) wrote a good answer on this topic so instead of paraphrasing him, I'll quote his answer:
The difference between optional and
nullable is the scope at which they
are evaluated. The definition of
'optional' talks about property and
field values and suggests that this
feature should be evaluated within the
runtime. 'nullable' is only in
reference to database columns.
If an implementation chooses to
implement optional then those
properties should be evaluated in
memory by the Persistence Provider and
an exception raised before SQL is sent
to the database otherwise when using
'updatable=false' 'optional'
violations would never be reported.
So I tried the #Basic(optional=false) annotation using JPA 2.1 (EclipseLink) and it turns out the annotation is ignored in actual usage (at least for a String field). (e.g. entityManager.persist calls).
So I went to the specification and read up about it.
Here is what the spec has to say:
http://download.oracle.com/otndocs/jcp/persistence-2.0-fr-oth-JSpec/
Basic(optional): Whether the value of the field or property may be
null. This is a hint and is disregarded for primitive types; it may be
used in schema generation.
So I think this sentence explains the real use case for Basic(optional) it is used in schema generation. (That is: when you generate CREATE TABLE SQL from Java Entity classes. This is something Hibernate can do for example.)

Does #JoinTable has a property of "table" or not?

The following is copied from hibernate's document. (http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e2770)
#CollectionOfElements
#JoinTable(
table=#Table(name="BoyFavoriteNumbers"),
joinColumns = #JoinColumn(name="BoyId")
)
#Column(name="favoriteNumber", nullable=false)
However, when I put this in practice, I just found that #JoinTable has no "table" property, instead it has a "name" property to specify the table name. But I need "table" property to specify indexes.
What's going on here? I'm almost driven crazy!
No, it doesn't, this sample is not accurate. Just in case, the #IndexColumn annotation that you see in this sample has nothing to do with a database index, it is used to store the index number of an element in an indexed collection. But I guess you're aware of that.
Actually, I'd suggest to raise a Jira issue specifying your use case and your database dialect (it seemts that generating an index on the FK works with some dialects, like MySQL, but doesn't with say Oracle).

Java Persistence / JPA: #Column vs #Basic

What is the difference between #Column and #Basic annotations in JPA? Can they be used together? Should they be used together? Or does one of them suffice?
#Basic signifies that an attribute is to be persisted and a standard mapping is to be used. It has parameters which allow you to specify whether the attribute is to be lazily loaded and whether it's nullable.
#Column allows you to specify the name of the column in the database to which the attribute is to be persisted.
If you specify one without the other then you get default behaviour which is sensible, so commonly folks use only one with the exception of special cases.
So if we wanted a lazy loading of an attribute and to specify a column name we can say
#Basic(fetch=FetchType.LAZY)
#Column(name="WIBBLE")
If we neeed the default, non-lazy behaviour then just the #Column would have been sufficient.
In addition to #djna's answer, it is worth noting that #Basic should be compared with #OneToMany, #ManyToOne and #ManyToMany. Only one of these can be specified on any property.
#Column and #JoinColumn can be specified along with any of these to describe the database column properties.
These are two sets of annotations that can be used together, but only one annotation of each set can be used at a time.
It is worth noting that Basic is designed for primitive fields
http://en.wikibooks.org/wiki/Java_Persistence/Basic_Attributes
A basic attribute is one where the attribute class is a simple type such as String, Number, Date or a primitive. A basic attribute's value can map directly to the column value in the database.
The types and conversions supported depend on the JPA implementation and database platform. Any basic attribute using a type that does not map directly to a database type can be serialized to a binary database type.
The easiest way to map a basic attribute in JPA is to do nothing. Any attributes that have no other annotations and do not reference other entities will be automatically mapped as basic, and even serialized if not a basic type. The column name for the attribute will be defaulted, named the same as the attribute name, as uppercase.
The #Basic annotation are applied to JPA entities, and the of #Column are applied to the database columns
#Basic annotation's optional attribute defines whether the entity field can be null or not; on the other hand,
#Column annotation's nullable attribute specifies whether the corresponding database column can be null
We can use #Basic to indicate that a field should be lazily loaded
The #Column annotation allows us to specify the name of the mapped database column
#Basic annotation marks the property as not optional on the Java object level. And (nullable = false) on the column mapping, is only responsible for the generation of a NOT NULL database constraint.

Categories

Resources