1

i'm a beginner with Hibernate, Spring, JPA frameworks. For moment, i'm trying to make a simple architecture with Spring 3.1.1 - JPA with Hibernate 4 Implementation.

For the moment, in order to not be dependant of my database, i created some ids with TableGenerator :

@Id
@Column(name = "AIR_ID", unique = true, nullable = false)
@TableGenerator(name="aircraftSeqStore", 
    table="T_S_APP_SEQ_STORE_AST", 
    pkColumnName="AST_SEQ_NAME",
    valueColumnName = "AST_SEQ_VALUE",
    pkColumnValue = "T_R_AIRCRAFT_AIR.AIR_ID", 
    allocationSize=1)
@GeneratedValue(strategy=GenerationType.TABLE, 
    generator="aircraftSeqStore")       
private Integer id;

After my research, and after reading "dont-let-hibernate-steal-your-identity" article, i don't really understood how to manage my ids.

Should i modify my entities to replace them with an assigned value (how to do it in JPA ?) and should i generate an UUID to affect the ids directly at the creation of the transient object ?

In many tables, i have some easy datas (id, name). I thought i could manage the hashcode and equals methods on name properties which are unique, but not affected at the creation of the object too....(so i think same pb with id which is null ?).

For information, i have an entity which represent a multi join table (3 FK in this join table).

So what do you advice to me ? Is it not bad of generate UUID for performance ?


EDIT :

Is this entity viable ?

@Id
@Column(name = "AIR_ID", unique = true, nullable = false)
@TableGenerator(name="aircraftSeqStore", 
    table="T_S_APP_SEQ_STORE_AST", 
    pkColumnName="AST_SEQ_NAME",
    valueColumnName = "AST_SEQ_VALUE",
    pkColumnValue = "T_R_AIRCRAFT_AIR.AIR_ID", 
    allocationSize=1)
@GeneratedValue(strategy=GenerationType.TABLE, 
    generator="aircraftSeqStore")       
private Integer id;

@Column(name = "AIR_BUSINESS_ID", unique = true, nullable = false)
private String uuid = IdGenerator.createId();

public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || !(o instanceof Aircraft))
        return false;

    Aircraft other = (Aircraft)o;

    if (uuid == null) return false;
    return uuid .equals(other.getUuid ());
}

public int hashCode() {
    if (uuid  != null) {
        return uuid .hashCode();
    } else {
        return super.hashCode();
    }
}

Thank you.

MychaL
  • 969
  • 4
  • 19
  • 37

3 Answers3

3

As with every question the full, but seldom usefull, answer is: It depends.

The more helpful variant is:

I use GenerationType.Auto most of the time, and do NOT implement equals and hashcode.

The result is:

  • you are fine comparing entity objects as long as they live in the same session, since hibernate will ensure that each database row is represented by a single instance per session.

  • equals and hashcode are stable over time, so you can put your objects in HashSets, change the objects and still get them out again.

  • If you want to work with objects from different Sessions you have to explicitly compare ids or ids + hashcode or some business key, possibly by implementing a Comparator. The extra effort put in deciding what to use and to implement it will remind you that you are actually doing something going against the grain of Hibernate.

About performance: Depending on the database and the use case UUIDs migh cost performance because they are rather large, or gain performance, because they can get created on the client thus saving a database roundtrip. Most of the times other glitches in the application (especially when using Hibernate) are way bigger then any effect of the ID Generation.

Shivan Dragon
  • 15,004
  • 9
  • 62
  • 103
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • +1. Really, this is a text book example of the "impedance mismatch" thing. You can't really rely on having hashcode and equals behavior from Hibernate/JPA pojo's as you'd have from "regular" instances due to the fact that these are not regular object instances. Involving the db id field in the hashcode is not possible, and even if you do manage to spot a bunch of other fields (other than id) that you can use to calculate hashcode, you risk ending up with a pretty "heavy" hashcode method, which results in performance issues when called a lot (like when having your objects placed in a HashSet) – Shivan Dragon Aug 10 '12 at 10:38
  • Actually, being a beginner, I have a lot of trouble understanding all the issues and impacts associated with the implementation of equals / hashcode. I do not handle very good English either (thanks google translation), so sometimes some of the concepts found on the net are unknown to me. – MychaL Aug 10 '12 at 12:25
  • All I understand is that for a transient object, if it has a set and that he injects new objects can cause errors. By working on ids that are not yet affected (null) will cause overwriting of data. And in other cases, the unnecessary creation of data in base. Now I'm not in AUTO mode generation identifiers. I manage this with a table that stores the ID incremental. Me is it possible to use it without override equals / hashcode? Or should I add to my table and my new entities that would be self-generated field (the creation of the entity) via a static class UUID generation? – MychaL Aug 10 '12 at 12:25
0

Usually i use:

    @Id
@GeneratedValue(strategy=GenerationType.AUTO)     
    private Integer id

and let the persistence provider to chose the right one. Hope this help you

FrancescoAzzola
  • 2,666
  • 2
  • 15
  • 22
  • Not really. I have a database which cannot auto-generated some IDs, and that doesn't answer if with Hibernate new version it still interesting to manage a business-id. – MychaL Aug 10 '12 at 12:08
0

I recently asked a question that explores an alternative to the usual pattern: Are there any gotchas with this JPA "cached hashCode" pattern?

I included an example of what I usually do with @Entity classes - generating UUIDs on construction. The probability of a UUID collision is so small that you'd be best worrying about cosmic rays. Some people don't like UUIDs because they feel there is a performance penalty. I've not seen any change in performance versus Integer, but I think the chance of an Integer collision is small enough to make it a concern.

@Id
private UUID id = UUID.randomUUID();

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (!(obj instanceof MY_CLASS) || id == null)
        return false;
    MY_CLASS other = (MY_CLASS) obj;
    return id.equals(other.id);
}

@Override
public int hashCode() {
    Preconditions.checkNotNull(id, "id must be set before @Entity.hashCode can be called");
    return id.hashCode();
}

Sometimes I want to check if the actual data itself matches, in which case I create a method like this:

public boolean hasSameProperties(Note other) {
    Preconditions.checkNotNull(other);
    if (this == other)
        return true;
    return Objects.equal(source, other.source)
            && Objects.equal(title, other.title)
            && Objects.equal(tags, other.tags)
            && Objects.equal(contents, other.contents);
}
Community
  • 1
  • 1
fommil
  • 5,757
  • 8
  • 41
  • 81
  • Unfortunately, i already have the database. And ids are not prepared for a UUID value. So my idea was to add an attribute/column to store this UUID and to override equals/hashcode methods. But it seems equals/hashcode methods are not really necessary with JPA, and new Hibernate version. – MychaL Aug 10 '12 at 12:12