36

There are always so many questions related to issues with detached entities!

First, they often cause LazyInitializationException in Hibernate. Yes, there are another persistence providers, which don't throw exceptions, but I think that they have some problems with consistency. Consider we have A and B entities that there is reference (@ManyToOne) from A to B that is required to be non-null.

We started our session, loaded A instance and then closed session. After that we try to obtain a reference to B. And assume that another transaction just deleted both our A and B instances. So when we query from database we can't find appropriate B instance and get null!

So our contract is violated. Some code that relies on fact that a.getB() returns an object will throw an NullPointerException. With persistent entities this is impossible because we have all lazy loading in the same transaction with obtaining object itself, so all operations are atomic (if we have a proper transaction isolation of course).

Also there are problems when you want to store persistent and detached entities in one Set. It that case you should always override equals and hashCode, which usually looks awkward, as I can't see a really good way to do it.

To get a detached entity back into EntityManager you should use merge which is glitchy.

So my question is: is there is a reasonable scenario where detached entities are really needed? Furthermore, when do you have to mix detached and persistent entities and merge detached entities into a new EntityManager?

Jaumzera
  • 2,305
  • 1
  • 30
  • 44
Alexey Andreev
  • 1,980
  • 2
  • 17
  • 29
  • 3
    I tend to just use find() to make entities attached again before I start to modify their state in the code and avoid merge() altogether. It just makes the code more dumb and thus easier to manage. But that's me. – Gimby Feb 07 '14 at 10:26
  • 1
    There's one context in which find must be used carefully. When retrieving many entities of the same class, calling find in a loop can be a performance killer. It's especially true when the entity is part of an class hierarchy (left outer joins aren't free). Another strategy should be used to deal with detached entities for these situations. – Marc-André Feb 10 '14 at 04:41

6 Answers6

20

I will explain why that scenario should not occur and why we need detached entities.

Consider you are in a JTA transaction (JPA requires support for it) and fetch a. Now you can call a.getB() either (1) in this transaction (i.e entity a is managed) or (2) when a is detached.

Scenario 1: now depending on your transaction isolation level, you might see or might not see what other transactions do. For example, if you have the SERIALIZABLE isolation level, then you will successfully fetch a.getB(), even if that row was deleted in a concurrent transaction. If that row was already deleted and your transaction sees that, it means that either your DB is inconsistent (no foreign key) or that you used the wrong transaction isolation level.

Scenario 2: the entity a is detached. When a LazyInitializationException is thrown, that means to me that you called a.getB() too late in order to guarantee a consistence in your application (as a is not managed anymore). In order to solve the problem you simply call it earlier when the entity is still managed. A NPE cannot occur.

Why we need the DETACHED STATE? Well, we need a state in which the changes to an entity instance are not tracked. Why?

Example 1: suppose you receive an entity (with persistent identity) in the EJB layer and that there were no detached state (meaning all entities should be managed). But we need to do a validation before persisting the entity. If that entity would be automatically managed, its changes would be automatically persisted to DB. So this new state was introduced.

Example 2: you receive in the EJB layer an entity, any you need to update ONLY 5 fields of 10 from that entity. If that entity would get automatically into the managed state, all 10 fields would be persisted. The solution in this case is to fetch a managed entity and to update the 5 fields ONLY in that entity.

Jaumzera
  • 2,305
  • 1
  • 30
  • 44
V G
  • 18,822
  • 6
  • 51
  • 89
  • 8
    I can't understand both of your examples. Why and from where do you receive these entities? If you receive them in a context of a transaction, why they come detached? If you receive them outside of a transaction, why do we get entities instead of DTOs? – Alexey Andreev Feb 07 '14 at 09:21
  • You receive them from the WEB Layer (e.g a Rest Resource or a Servlet). They come detached, because no one merged them. DTOs are actually a pattern to transfer data between different interfaces. You could use it between the EJB/Web layer, but that makes the EJB/Business layer too complicated (with too many responsibilities). That's why I would recommend using them only at the border Web Layer/Web Client (and between the WebLayer/EJB Layer use directly entities). – V G Feb 07 '14 at 09:36
  • Oh, I'm sorry, I am just not good enough at JEE terminology. Consider, we have our client, which issues its request in terms of DTOs. Server receives client's request and calls several business methods, each acts in a separate transaction. But why don't we have a single transactions per request? I suggest, there are cases when we have an additional long-running processing that is not related to a database. – Alexey Andreev Feb 07 '14 at 09:37
  • I reformulated my first example. Also please understand, that JPA is something that gives freedom to the world, without forcing it to implement DTOs or to use another pattern. – V G Feb 07 '14 at 09:38
  • 1
    Usually you have a SINGLE transaction per request, but of course there are scenarios when you need multiple transactions. Suppose you want to log every request, along with doing the business logic. These should be different transactions. Or suppose you should emit invoices for 10 users. If an invoice cannot be emitted, should not block other invoices from being generated. You do that by using a transaction for every user/invoice. – V G Feb 07 '14 at 09:43
  • But I think, that in cases when you haven't to care about performance, it is considerably to have transaction-per-request scenario to increase maintainability of code. And I would merge as soon as possible. – Alexey Andreev Feb 07 '14 at 09:44
  • @AndreiI why modifiying the entities outside the business layer? what is the responsibility of business and web layer? shouldn't all modifications on entities happen inside the business layer?, ofc business layer can export entities to make things simpler but for read only, if web layer modify entities that means the web layer is applying some business rules on entities which should occurs only inside the business layer. – La VloZ Merrill Nov 29 '18 at 10:50
18

Detached - a detached instance is an object that has been persistent, but its Session has been closed. The reference to the object is still valid, of course, and the detached instance might even be modified in this state. A detached instance can be reattached to a new Session at a later point in time, making it (and all the modifications) persistent again. This feature enables a programming model for long running units of work that require user think-time. We call them application transactions, i.e., a unit of work from the point of view of the user.

References Hibernate DOc

Why?

The Session caches every object that is in a persistent state (watched and checked for dirty state by Hibernate). If you keep it open for a long time or simply load too much data, it will grow endlessly until you get an OutOfMemoryException. One solution is to call clear() and evict() to manage the Session cache,keeping a Session open for the duration of a user session also means a higher probability of stale data.

References Again Hibernate Doc

I bet you haven't read through hibernate documentation itself, It has scenarios explaining them too :)

Simple Explanation:With reference to persistent objects..

Suppose a user has to update a form, you get the details of user in from through UserObject, This user object is persistent with session. Now if user doesn't submit the form, your session is open until server session expires, how long will you wait? If you have used getCurrentSession, another form request comes while previous one is not submitted, you have got dirty data now!! What if your object is waiting for a data that is to come for a web-service and it taking long enough, will you still keep session open, object persistent with session?

DarkHorse
  • 2,740
  • 19
  • 28
  • 2
    Hibernate docs explain a motivation of a detached state, but they don't explain why do I need detached entities. As for me, I usually throw away all the detached entities. Furthermore, I very rarely use `detach` and `clear` methods. Instead, I let entities to become detached when session closes and I never reuse any of the session's entities then. I just can't understand motivation of reusing entities after they being detached. – Alexey Andreev Feb 07 '14 at 09:25
  • 2
    Such methods become useful for the rare case where you are working with large volumes of objects and the persistence store might grow to such proportions that it starts to make a noticeable affect on performance. If you know that entities are no longer needed to be attached, you can then manually evict them and perhaps prevent having to go to the next step of complexity, which is to work in batches / multiple transactions. – Gimby Feb 07 '14 at 10:23
  • @DarkHorse - Rephrasing what you have stated, am I right to think of _detach_ as a way of "clearing the cache" - I mean, if I did some changes on an entity, I want other threads to get the newly updated value, not the one that EntityManager has cached ? – Victor Apr 10 '20 at 08:40
2

Detached entities exists only to minimize the time your data is locked due to a transaction, maximizing the number of simultaneous users. Of course, this comes with a cost, and you listed them. but since merging conflicts are usually rare, people accept some rare bugs.

You see, data conflics will always exist, but they occur less when the transaction is short :-)

Leo
  • 6,480
  • 4
  • 37
  • 52
0

It could be that an entity is seen as detached because it has the same ID as an entity in the persistence store. Imagine you got the entity from outside of the application. It could be that this entity is seen as detached when trying to persist it. There for you have to attach it again with, indeed, the merge.

I can't really imagine other situations and I'm curious for the other answers.

GregD
  • 1,884
  • 2
  • 28
  • 55
  • 1
    Why do i get *entity* from **outside** of the application, instead of getting *DTOs*? How this *outside* knows which entities do I operate? – Alexey Andreev Feb 07 '14 at 09:26
  • I agree with you to use DTO there, as with JPA entities there are often case when you should get a whole table to transfer an entity. Tree hierarchy whith `parent` and `children` properties is the example. – Alexey Andreev Feb 07 '14 at 09:39
0

Detached entities (eagerly fetched) could work as DTOs in some cases. Probably not something that should be done in an enterprise application, but e.g. a java se based network game, where both the server and client come from same codebase, the player state could be reprented as entity and be transfered to/from server and persisted there.

Not sure that it would be a better choise than proper DTO, but it could be technically done.

Bjarne Boström
  • 227
  • 1
  • 4
  • 14
0

For instance, suppose you have a RESTful interface with a method for retrieving an JSON-serialized object by its id to the caller and a method that receives an updated version of this object from the caller. An entity that passed through such serialization/deserialization will appear in a detached state.

check this, and read 3.3 merge