How hibernate uses equals() and hashCode()? - java

If you load an entity from db and modify it somehow, will hibernate use equals/hashCode to compare current state of entity with it's snapshot to determine if sql update needs to be performed?
If it does such comprasions, I have another question: if equals will return true, will hibernate think that entity did not changed or attempt to use it's default comprasion (to be sure)?

Please see Equals and HashCode from the JBoss Community website. From there:
To avoid this problem we recommend using the "semi"-unique attributes
of your persistent class to implement equals() (and hashCode()).
Basically you should think of your database identifier as not having
business meaning at all (remember, surrogate identifier attributes and
automatically generated vales are recommended anyway). The database
identifier property should only be an object identifier, and basically
should be used by Hibernate only. Of course, you may also use the
database identifier as a convenient read-only handle, e.g. to build
links in web applications.
In other words, Hibernate uses equals and hashCode for identity, not to see if an object has been modified. It uses attribute by attribute comparisons for that.

Not an Hibernate expert, but you may find this section of manual enlightening.

Related

hashCode() method for related entities

I read that when using JPA you should implement hashCode()/equals() for your entities.
So Eclipse for example has this nice feature to generate those methods for the classes.
But what fields do i have to choose?
I read that choosing the Long id; field of your entity is not a good idea. (right?, why?)
One should use a business key (some fields of the entity which can be used to identify the entity. right?) in the hashCode()/equals() methods.
Considering following scenario:
1:n relation between A and B...
is it a good idea to use those references in the hashcode() method?
if i do so i sometimes run into java.util.ConcurrentModificationException or Stackoverflow exceptions.
What about collections variables? i think i should not use those in my hashcode() function...
can somebody give me hints?
Consider using the fields (as few as possible) that will uniquely identify the object. If it were a Person it might be first, middle and last name. Or better still, Social Security Number if US Person. I don't see any issue with using a DB ID so long as the table cannot contain duplicate entities. In general, the identity of an object should not require checking the identities of it's associated objects (the 1:n relationship) but just the local fields.
Equals and hashcode methods should be always implemented either on primary key or on your business key this is necessary if you want to adhere to requirements of your persistent manager. Check here
You can implement your own logic in hashcode to get the unique number.For example
you can do some combination of ^-ing
(XOR-ing) a class's instance variables (in other words, twiddling their bits), along
with perhaps multiplying them by a prime number.

Hibernate, fetch, HQL and hashCode()

I have a HQL query something ala'
SELECT myclass
FROM
MyClass myclass JOIN FETCH
myclass.anotherset sub JOIN FETCH
sub.yetanotherset
...
So, class MyClass has a property "anotherset" , which is a set containing instance of another class, lets call it MyClassTwo. And, class MyClassTwo has a property yetanotherset which is a set of a third type of class (with no further associations on it).
In this scenario, I'm having trouble with the hashCode implementation. Basically, the hashCode implementation of MyClassTwo, uses the "yetanotherset" property, and on the exact line it accesses the yetanothertest property, it fails with a LazyInitializationException.
org.hibernate.LazyInitializationException: illegal access to loading collection
I'm guessing, this is because the data from "yetanotherset" hasn't been fetched yet, but how do I fix this? I don't particularly like the idea of dumbing down the hashCode to ignore the property.
Additional question, does HQL ignore fetch=FetchType.EAGER as defined in XML or annotations, it seems like it does. But I cant verify this anywhere.
Implementing hashCode() using a mutable field is a bad idea: it makes storing the entity in a HashSet and modifying the mutable property impossible.
Implementing it in terms of a collection of other entities is an even worse idea: it forces the loading of the collection to compute the hashCode.
Choose a unique, immutable property (or set of properties) in your entity, and implement hashCode based on that. On last resort, you have the option of using the ID, but if it's autogenerated, you must not put it in a Set before the ID is generated.
This is hibernate's most famous exception and it is exactly as you described it. The session has been disconnected, transaction closed, and you are attempting to access this collection. JOIN FETCH in your HQL should force EAGER loading to occur regardless of whether than annotation is present.
I suspect that your annotations are malformed, you have missing or out of date jars, or some other problem of that type.
Bump your Hibernate logging level up to generate the SQL hibernate.SQL=debug and investigate exactly what SQL is being executed up to where you see this exception. This should indicate to you whether your hibernate configuration is behaving the way you think its configured.
Post more of your code and the logs and someone might be able to help you spot the error.

Entities in domain driven design

I am reading Eric Evans book about DDD and I have a question to the following quote. How do you make your equals() method when you should not use the attributes? I am using JPA and I have a id attribute which is unique but this is not set until you actually persist the entity. So what do you do? I have implemented the equals method based on the attributes and I understand why you shouldn't because it failed in my project.
Section about entities:
When an object is distinguished by its identity, rather than its
attributes, make this primary to its definition in the model. Keep the
class definition simple and focused on life cycle continuity and
identity. Define a means of distinguishing each object regardless of
its form or history. Be alert to requirements that call for matching
objects by attributes. Define an operation that is guaranteed to
produce a unique result for each object, possibly by attaching a
symbol that is guaranteed unique. This means of identification may
come from the outside, or it may be an arbitrary identifier created by
and for the system, but it must correspond to the identity
distinctions in the model. The model must define what it means to be
the same thing.
http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
Couple approaches possible:
Use a business key. This is the most 'DDD compliant' approach. Look closely at domain and business requirements. How does your business identify Customers for example? Do they use Social Security Number or phone number? How would your business solve this problem if it was paper-based (no computers)? If there is no natural business key, create surrogate. Choose the business key that is final and use it in equals(). There is a section in DDD book dedicated to this specific problem.
For the cases when there is no natural business key you can generate UUID. This would also have an advantage in distributed system in which case you don't need to rely on centralized (and potentially unavailable) resource like database to generate a new id.
There is also an option to just rely on default equals() for entity classes. It would compare two memory locations and it is enough in most cases because Unit Of Work (Hibernate Session) holds on to all the entities (this ORM pattern is called Identity Map). This is not reliable because it will break if you use entities that are not limited to the scope of one Hibernate Session (think threads, detached entities etc)
Interestingly enough, 'official' DDD sample uses a very lightweight framework where every entity class is derived from Entity interface with one method:
boolean sameIdentityAs(T other)
// Entities compare by identity, not by attributes.
If the object is not persistent yet, then is there any harm in comparing 2 objects based on their attributes?
I am not sure why this failed in your project, but in my experience, comparison based on attributes almost always is slippery slope if your attributes are not final. That means, 2 objects that are equal now, may not be equal after sometime. This is very bad.
Given that most Java classes are written along with their accessors, equals comparing attributes are said to be a bad idea.
However, I would probably first check to see if the ID field is not null. If it is null, I would fall back to attribute comparison. If it is not null, then just use it and not do anything else. Does this make sense?
Given Person class with attributes name, surname. When Person at the age of 21 changes its name is it still the same Person (equals gives true)?
If you write equals basis on attributes, then, it would not be the same person, so in my opinion the best approach is to test equality of entities basis on their business identifier (unique and immutable over the whole entity lifecycle).
Another solution could be to use an UUID field in your entity.
In this case, you could use the UUID as primary key or just for equals.
#Entity
public class YourEntity{
#Id
private String uuid = UUID.randomUUID().toString();
// getter only...
}

How does Hibernate detect dirty state of an entity object?

Is it using some kind of byte codes modification to the original classes?
Or, maybe Hibernate get the dirty state by compare the given object with previously persisted version?
I'm having a problem with hashCode() and equals() methods for complicated objects. I feel it would be very slow to compute hash code if the object has collection members, and cyclic references are also a problem.
If Hibernate won't use hashCode()/equals() to check the dirty state, I guess I should not use equals()/hashCode() for the entity object (not value object), but I'm also afraid if the same operator (==) is not enough.
So, the questions are:
How does Hibernate know if a property of an object is changed?
Do you suggest to override the hashCode()/equals() methods for complicated objects? What if they contains cyclic references?
And, also,
Would hashCode()/equals() with only the id field be enough?
Hibernate uses a strategy called inspection, which is basically this: when an object is loaded from the database a snapshot of it is kept in memory. When the session is flushed Hibernate compares the stored snapshot with the current state. If they differ the object is marked as dirty and a suitable SQL command is enqueued. If the object is still transient then it is always dirty.
Source: book Hibernate in Action (appendix B: ORM implementation strategies)
It's important to notice however that Hibernate's dirty-checking is independent of the methods equals/hascode. Hibernate does not look at these methods at all (except when using java.util.Set's, but this is unrelated to dirty-checking, only to the Collections API) The state snapshot I mentioned earlier is something similar to an array of values. It would be a very bad decision to leave such a core aspect of the framework in the hands of developers (to be honest, developers should not care about dirty-checking). Needless to say that equals/hascode can be implemented in many ways according to your needs. I recommend you to read the cited book, there the author discuss equals/hascode implementation strategies. Very insightful reading.
Hibernate default dirty checking mechanism will match all mapped properties of all currently attached entities against their initial loading-time values.
You can better visualize this process in the following diagram:
Hibernate does a field-by-field checking to determine the dirtiness of an entity.
So hashCode/equals do not come into the picture at all.
Actually, the field-by-field dirty checking done by Hibernate can be quite costly in terms of performance.
So it provides interfaces like Strategy or Interceptor.findDirty() to handle the same.
Following post explains this in greater detail (alongwith some ideas for applications to optimize it fully): http://prismoskills.appspot.com/lessons/Hibernate/Chapter_20_-_Dirty_checking.jsp
Probably worth adding, as this distracted me for a while: if you are using a CustomType on your persistent object, equals is used for the dirty check.
This stack is from setting a breakpoint in the equals method of my custom data type in Hibernate, MyType, then triggering a transaction and seeing the equals being called.
equals:68, MyType (xxxxxx)
isEqual:105, CustomType (org.hibernate.type)
isSame:119, AbstractType (org.hibernate.type)
isDirty:79, AbstractType (org.hibernate.type)
isDirty:249, CustomType (org.hibernate.type)
findDirty:316, TypeHelper (org.hibernate.type)
findDirty:4622, AbstractEntityPersister (org.hibernate.persister.entity)
dirtyCheck:585, DefaultFlushEntityEventListener (org.hibernate.event.internal)
isUpdateNecessary:242, DefaultFlushEntityEventListener (org.hibernate.event.internal)
onFlushEntity:169, DefaultFlushEntityEventListener (org.hibernate.event.internal)
flushEntities:232, AbstractFlushingEventListener (org.hibernate.event.internal)
flushEverythingToExecutions:92, AbstractFlushingEventListener (org.hibernate.event.internal)
onAutoFlush:50, DefaultAutoFlushEventListener (org.hibernate.event.internal)
accept:-1, 765785095 (org.hibernate.internal.SessionImpl$$Lambda$1238)
fireEventOnEachListener:102, EventListenerGroupImpl (org.hibernate.event.service.internal)
autoFlushIfRequired:1327, SessionImpl (org.hibernate.internal)
does the dirty checking also involve any attached AttributeConverters? what if the value in the java object stays the same but the AttributeConverter logic is changed and does lead to different database values.
so read entity with old AttributeConverter config, write entity with new AttributeConverter config.
the java object stays the same for old and new AttributeConverter but the database values changes because of old and new AttributeConverter config.
It is simple-- when you load/get entity object by id and then set its new field values by setter method and close session without calling update() method. then hibernate automatically update the changed value in the table without affecting other fields. and at the same time entity object is in dirty state.

DDD: Entity and its identifier

I have an entity in my system, which naturally needs an identifier so that it can be uniquely identified. Assuming the database is used for generating the identifier with Hibernate, using the native strategy, then obviously the application code is free of this responsibility of assigning identifiers.
Now, can an instance of that entity be considered valid before it is persisted and gets its identifier?
Or should I use some other strategy to assign my entities their identifiers so that it gets its identifier when its constructor is called?
That's an extensive topic, but here are two possibilities:
define your hashCode() and equals(..) contracts based on business keys. For example, for a User entity, this would be the username, rather than the auto-generated id. Thus you will be able to use the entity in collections before it is persisted
use UUID as a primary key, and handle the generation yourself. See this article by Jeff Atwood and this article demonstrating a way to use it with Hibernate
(Since you mention DDD and hibernate, take a look at this article of mine)

Categories