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.
Related
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
I'm new in Hibernate. What is the difference between
#Id
#GeneratedValue
private Integer id;
and
#Id
#GeneratedValue
#Column(name="id", unique=true, nullable=false, etc)
private Integer id;
What is the reason of defining this if we already did it creating database? Does Hibernate warn us when we break these constraints (not in this example since it's auto generated value)? Does it create table when there isn't one?
The only reason is if the column is named differently, for example in a USER table, if the id column is called USER_ID, you might want to map that to a User object, on the field id.
The unique and nullable attributes are not used, as PK are unique and non-null. Read the javadoc of #Column to understand what else you can define there.
As you mentioned, if you create your DB from scripts (it's actually a bad practice to create your production DB from the JPA annotations), the only relevant attribute is the name... the other ones are not used for #Id columns or are used to autogenerate the DDL.
A slight word of caution, sometimes the attribute nullable influences on how updates are ordered. As a good practice, I always set it to false on mandatory associations (as otherwise Hibernate might decide clear the association and set the column to null... and then do another update with the new ID.).
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.
I have seen this question at SO which tends to lead towards Primitives and also seen this one from coderanch which tends to lead towards wrappers. Both are slightly old too.
I do not have any special needs just want to know a standard good practice.
Examples on web are mixed too. e.g some with go like this:
#Id
#Column(name = "CUSTOMER_ID")
public long customerId;
Others with Wrappers:
#Id
#Column(name = "CUSTOMER_ID")
public Long customerId;
The difference between the two is nullability. the primitive type is unable to be null, while the "Wrapped" type can be null.
I prefer to use the wrapped type as you can tell if the object has been saved/loaded to/from the database whether or not the id value is null.
I don't think there is a "best practice" here, maybe a matter of style?
Hibernate recommends you:
We recommend that you declare consistently-named identifier properties
on persistent classes and that you use a nullable (i.e.,
non-primitive) type. more
I think that answer is included in nullable element in #Column annotation. If it can be nullable than wrapped primitive is ok. But on nullable=false columns ( as ID is) primitives are better. You will get extra checking because null cannot be cast to int/long.
If you use primitives it will always hold a default value, in this case 0L for long, even if the value is not there in the database. And if you use the wrapper object it will be having a null value if the value is not in the database or the entity is not persisted yet.
From an Hibernate point of view, it doesn't change anything as Hibernate uses the same Hibernate type to represent them.
However, as pointed out by Bytecode Ninja, you can't distinguish the default value of a primitive int 0 from a an assigned 0 while there is no possible ambiguity with a null (a null id always means a new entity), which is why I prefer to use a nullable wrapper type.
And this is the Hibernate recommendation. From the Reference Documentation:
4.1.2. Provide an identifier property (optional)
Cat has a property called id. This property maps to the primary key column of a database table. The property might have been called anything, and its type might have been any primitive type, any primitive "wrapper" type, java.lang.String or java.util.Date. If your legacy database table has composite keys, you can use a user-defined class with properties of these types (see the section on composite identifiers later in the chapter.)
The identifier property is strictly optional. You can leave them off and let Hibernate keep track of object identifiers internally. We do not recommend this, however.
In fact, some functionality is available only to classes that declare an identifier property:
Transitive reattachment for detached objects (cascade update or cascade merge) - see Section 10.11, “Transitive persistence”
Session.saveOrUpdate()
Session.merge()
We recommend that you declare consistently-named identifier properties on persistent classes and that you use a nullable (i.e., non-primitive) type.
And I actually leverage this in my base class:
#MappedSuperclass
public class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Transient
public boolean isNew() {
return (this.id == null);
}
}
Please check the more details here:https://stackoverflow.com/posts/3537407/edit
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.