Should I use Primitives or wrappers in JPA2.0? - java

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

Related

Returning any field instead of a fixed value in Hibernate Hash Code [duplicate]

After reading several articles, threads and making some research, now I am completely confused regarding to implementing a proper equals and hashCode method in my Spring Boot app.
For example, I have the following class:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Recipe {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String title;
#Column(length = 100)
private String description;
#Column(nullable = false)
private Integer prepTime;
#Column(nullable = false)
private Integer cookTime;
#Column(nullable = false)
private Integer servings;
#Lob
#org.hibernate.annotations.Type(type = "org.hibernate.type.TextType")
#Column(nullable = false)
private String instructions;
#Column(nullable = false)
#Enumerated(value = EnumType.STRING)
private Difficulty difficulty;
#Column(nullable = false)
#Enumerated(value = EnumType.STRING)
private HealthLabel healthLabel;
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinColumn(name = "category_id", referencedColumnName = "id")
private Category category;
#OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true)
private List<RecipeIngredient> recipeIngredients = new ArrayList<>();
}
I have trouble for these issues below and trying to implement equals and hashCode methods properly:
1) As far as I know, when there is a unique field that can be used to differentiate one person from the other e.g. email or username, then it is enough ONLY use these fields in equals and hashCode method. Is that true?
2) If there is not any unique field except from id, then should I add ALL the fields (id and the others) to equals and hashCode method implementation?
3) When using Hibernate and Data JPA, should I follow a different approach than other situation as there are 4 states transient, managed, removed, and detached in JPA lifecycle? I think id field should not be used in this situation as it is not present in transient mode? Right?
When implementing equals() and hashCode() methods:
If there is a unique field that can be used to differentiate one object from another, use only that field in the implementation.
If there is no unique field, use all the fields including the id in the implementation.
When using Hibernate and Data JPA, do not use the ID field in the implementation as it is not present in the transient state, instead use fields that are present in all states such as unique fields or all fields.
The problem with equals and hashCode is that their contract is broken for any mutable entity and with JPA, there aren't really any other.
Ignoring JPA for a moment, by definition the id of an entity defines its identity.
So it should be used for equals and hashCode.
But this requires the id to be unmodifiable in an entity, but JPA requires a no args constructor and a way to set all properties, including the id.
Probably the best way around this is to
use the id.
make sure that equals and hashCode is never ever used before the id is set, and the id is never changed afterwards.
Not changing the id after it is once set is normally not a problem, since the id shouldn't change from one value to another.
The problem is creation of new instances.
Again instances returned by JPA aren't a problem, because JPA will fully initialise them before returning them to you.
Creating fresh instances in your application is the problem.
Here you have the following options:
create the instance and immediately assign a id. UUIDs are perfect for this.
They can be generated easily and efficiently on the application server.
This could be done in a static factory method on the entity class.
The drawback is that UUIDs are a pain to work with for humans, since they are long and basically random.
They are also large and eat more memory in the database than a traditional sequence number.
But the use cases with so many rows that this actually is a problem are rare.
generate the id in the database as most people do, and make sure that your new entity gets saved immediately after creation.
This could be nicely done in a custom method in a repository.
But it does require that you set all required properties in one place, which often can be a problem.
Using some other attribute which is supposed to be immutable, like the account name or an email works only for very few entities in the first place and even for those the fact that it is immutable now doesn't mean it stays that way.
Instead of trying to avoid the pitfalls created by JPA you could alternatively rely on it.
JPA guarantees that for a given class and id only one instance is in a persistence context.
Therefore, as long as you only work within a single session/transaction with an entity and don't try to compare detachd entities, there is no need to implement equals and hashCode at all.
as you are already using lombok, you can use #Data annotation as well:
#Data
All together now: A shortcut for #ToString, #EqualsAndHashCode, #Getter on all fields, #Setter on all non-final fields, and #RequiredArgsConstructor!

Boxed vs primitive type as entity id

In JPA (Hibernate implementation) which type is better to use for id of the entity:
Boxed type (e.g. Integer) or Unboxed type (e.g. int)?
A friend said that you should use Boxed types because when you create a new entity in your program, Hibernate sees that the id is null and understands that it should create a new row in database (In contrast if id is not null Hibernate may update an existing row in databse).
But the id of my entities was int and it worked well without any error and we know that the default value of primitive instance variables is 0. So he said that maybe hibernate treats 0 as special and assumes that the object is a new one.
Seems Current Documentation recommends to use Boxed Type.
We recommend that you declare consistently-named identifier attributes on persistent classes and that you use a nullable (i.e., non-primitive) type.
Well, we use non-primitives and we have a strong reason for it. Lots of our fields that are either int/Integer for example have an absolute business value of zero to be perfectly valid. Think of a debt field for example - it is more than OK if the field is zero, meaning you have no debt.
Problem is that with primitives, zero is a default value - so you might accidentally forget to set it for example via a setDebt, thus it might reach your database with a value that you never intended to go there. For this reason we use Integer with some validations that is should never be null for example; but even if we forget to add proper validations, that code will potentially break with a NullPointerException (preferably in tests) and I like an Exception more than inconsistent values in the database.
There is no difference between primitive (e.g., int) and its wrapper(e.g., Integer) for entity id. Both are valid according to JPA specification. JPA provider is smart enough to track the state and life cycle of an entity. When entity id is 0 (primitive type) or NULL(wrapper type), JPA provider will generate an id for the entity if id generator is configured. Zero is not regarded as a valid entity id if id is auto generated.
Tested both cases with Cmobilecom JPA, and it works equally well. Off course, no performance difference can be noticed.
Disclaimer: I am a developer of Cmobilecom JPA, a light weight JPA implementation for both Java and Android.
I prefer Boxed Type in entity model because that gives flexibility to use Boxed Type in generics.
For instance, here Entity model can have only the type that extends to Serializable for id. It will be useful later in service layer where we can perform various operations on primary key.
public interface BaseEntity<E extends Serializable> extends Serializable {
E getId();
}
Entity model could be like:
#Entity
public class PhoneNumber implements BaseEntity<Long> {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PHONE_NUMBER_ID")
private Long id;
Unique identifiers of entities and collections may be of any basic type except binary, blob and clob. (Composite identifiers are also allowed, see below.)
The basic value types have corresponding Type constants defined on org.hibernate.Hibernate. For example, Hibernate.STRING represents the string type.
We can think of it like this:
When we have a value x :: Int, then 'x' is a computation
which when evaluated will return either an Int or will
be bottom (undefined).
When the program runs and x is evaluated, suppose it evalutes to an
actual Int (not bottom). Then in the future any time x is evaluated,
instead of redoing the entire computation, we only want to get the value
out which we previously calculated.
What we do to accomplish this is to replace to thunk (computation) which
calculates x with a thunk which simply returns the value which was
computed before.
The problem is that every time you need to get x in the future, you have
to follow this pointer to the (trivial) code which returns a value. THis
gets expensive if you need these values frequently.
Enter unboxed values. An unboxed value is just that low-level value, not
wrapped inside a thunk. This means that it is strict in the sense that it
cannot be undefined without your program necessarily dying.

JPA entity, identify Business key

Lets say I'm writing a JPA entity. Very simple one. It has 3 properties:
public class MenuItem {
#Id
#GeneratedValue
private Long menuItemId;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private Type type;
#OneToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "colorId")
private Color color;
}
Now, lets say I need to override its equals/hashcode methods. According to this suggestion Implementing equals() and hashCode() I have to use some sort of "Business key equality". But I have doubts, what should I consider as a "Business" key here. Does it have to be all the properties except of ID, or Color can be excluded from it. Just seems unclear to me. Would be thankful if anyone can explain more on this topic.
The last statement in the reference is pure gold:
Note that a business key does not have to be as solid as a database
primary key candidate. Immutable or unique properties are usually good
candidates for a business key.
So in your case name and type would be good candidates. Assuming the Type would be an immutable object (you could still get away without that but you might experience some hard to detect bugs).
IF you would put a unique constraint on color then i would consider that in the equals / hashCode method also.

Hibernate defining table in #Entity

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.).

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