Making Entity Class Closed for Changes

Is there a way to update the entity classes in jpa automatically?

I used to take advantage of the JPA Modeler plugin some time ago for one of my projects. It does the trick when it comes to updating your jpa entities based on the database tables state.

Here is the link with some video tutorials: jpa-plugin

Changing the type of an entity preserving its ID

Hibernate attempts to make persistence as transparent as it possibly can - which means it tries to follow the same principles as normal Java objects. Now, rephrasing your question in Java, you'd get:

How can I convert an instance of B class into an instance of (incompatible) C class?

And you know the answer to that - you can't. You can create a new instance of C and copy necessary attributes, but B will always be B, never C. Thus the answer to your original question is - it cannot be done via JPA or Hibernate API.

However, unlike plain Java, with Hibernate you can cheat :-) InheritanceType.SINGLE_TABLE is mapped using @DiscriminatorColumn and in order to convert B into C you need to update its value from whatever's specified for B into whatever's specified for C. The trick is - you cannot do it using Hibernate API; you need to do it via plain SQL. You can, however, map this update statement as named SQL query and execute it using Hibernate facilities.

The algorithm, therefore, is:

  1. Evict B from session if it's there (this is important)
  2. Execute your named query.
  3. Load what-is-now-known-as-C using former B's id.
  4. Update / set attributes as needed.
  5. Persist C

How can I have a behavior-rich domain entity that adheres to Open-Closed Principle?

It's useful to keep the open-closed principle (OCP) in mind when designing classes, but it's not always practical or desirable to make classes "closed for modification" right away. I think the single responsibility principle (SRP) is much more useful in practice -- as long as a class only does one thing, it is okay to modify it if the requirements for that one thing change.

Moreover, SRP leads to OCP over time; if you find yourself changing a class often, you would eventually refactor it so that the changing portion is isolated in a separate class, thus making the original class more closed.

Should entity class be used as request body

You should create a DTO class and map it to persistence class. Refer this rule description for the same. Reason specified is

if a persistent object is used as an argument of a method annotated with @RequestMapping, it’s possible from a specially crafted user input, to change the content of unexpected fields into the database

Apart from this, using DTO we can omit some of the persistent object properties that we don't wish to be present/visible in presentation layer.

You can map DTO class to persistence entity in controller itself like below.

@RestController
@RequestMapping("books")
public class BookController {

@Autowired
BookRepository bookRepository;

@Autowired
ModelMapper modelMapper

@PostMapping
public Book saveBook(@RequestBody BookDTO modelBook) {
Book book = this.modelMapper.map(modelBook, Book.class);
return bookRepository.save(book);
}
}

ModelMapper is a framework that does the DTO to Entity and vice versa mapping. Check ModelMapper website.

You may refer answer and comments for more information about the same.

Should JPA Entity Manager be closed?

I suppose the answer is: it depends.

Your entity manager is the key to gain access to the context where entities reside. If your application is a JSE application, you have to consider what is the life expectancy of your context.

Let's consider that you will create an entity manager per user's request. So, while you are attending a given request, you will keep your entity manager open, and when you finish with it, you close it.

In a JSE application, you may have considered that you would like to keep your entity manager open the entire life of the application (supposing you're not dealing with big amounts of data) then you close it when your application shuts down.

Bottom line, when you open it and when you close depends entirely on your strategy and your design. You close it when you no longer need the entities in its context.

In your example, that is not evident, but since you're creating the EM in the method, you should close it before returning, otherwise, you will no longer have access to it again (unless you're keeping it in some registry, which is not evident in the code).

If you don't close it your entities will be kept as attached, even after you're done using them. Your context will be kept alive even when you can no longer access your EM.

The JPA Specification contains more details. In section 7.7 Application-managed Persistence Contexts it says:

When an application-managed entity manager is used, the application
interacts directly with the persistence provider's entity manager
factory to manage the entity manager lifecycle and to obtain and
destroy persistence contexts.

All such application-managed persistence contexts are extended in
scope, and can span multiple transactions.

The EntityManagerFactory.createEntityManager method and the
EntityManager close and isOpen methods are used to manage the
lifecycle of an application-managed entity manager and its associated
persistence context.

The extended persistence context exists from the point at which the
entity manager has been created using
EntityManagerFactory.createEntityManager until the entity manager is
closed by means of EntityManager.close.

An extended persistence context obtained from the application-managed
entity manager is a stand-alone persistence context it is not
propagated with the transaction.

[...] The EntityManager.close method closes an entity manager to
release its persistence context and other resources. After calling
close, the application must not invoke any further methods on the
EntityManager instance except for getTransaction and isOpen, or
the IllegalStateException will be thrown. If the close method is
invoked when a transaction is active, the persistence context remains
managed until the transaction completes.

The EntityManager.isOpen method indicates whether the entity manager
is open. The isOpen method returns true until the entity manager has
been closed.
To actually understand how this works it is vital to understand the relationship between the entity manager and the context.

So, as you can see the entity manager is the public interface through which you access your entities, however, your entities reside in a context, attached to your entity manager. Understanding the life cycle of the different types of contexts will answer your question.

Persistence contexts can be of different types. In Java EE applications, you can either have a transaction-scoped persistence context or a extended-persistence context. In the JSE application, the nature of the context is controlled by the developer.

When you ask for an entity to your entity manager, it looks for the entity in its attached context, if it finds the entity there, then it returns it, otherwise, it retrieves the entity from the database. Subsequent calls for this entity in context will return the same entity.

Transaction-scoped

In a Java EE application using the transaction-scoped persistence context, when you first access your entity manager, it checks if the current JTA transaction has a context attached if no context is yet present, a new context is created and the entity manager is linked to this context. Then the entity is read from the database (o from the cache if present) and it is placed into the context. When your transaction ends (commit or rollback), the context becomes invalid and whatever entities in it become detached. This is the classical scenario for stateless sessions beans.

@PersistenceContext(unitName="EmplService")
EntityManager em;

This also means that depending on how you design your transactions, you may end up with more than one context.

Extended-Persistence Context

In a Java EE application with stateful session beans you might like the context to survive multiple bean invocations, since you don't like to commit until the bean has been marked for removal, right? In those cases, you need to use an extended persistence context. In this case, the persistence context is created when it is first needed, but it won't become invalid until your mark the stateful bean for removal.

@PersistenceContext(unitName="EmplService", type=PersistenceContextType.EXTENDED)

This means that, regardless of the instance of the entity manager that gets injected into this bean in subsequent calls of the stateful session beans methods, you can be sure you will always access the same context, and therefore, even subsequent calls will return the same instance, because it is the same context.

Also, your changes will not be flushed until the bean is marked for removal or you manually flush them.

Application-Managed

You can always instantiate manually your entity manager factory and your entity manager. This is what you would typically do in a JSE application, is that right?

For this kind of applications you typically do not have a container to deal with the JTA transactions, right? So you use resource-local transactions and you are responsible for manually committing or rolling back changes.

For this kind of application, when you instantiate your entity manager, a context is automatically attached to it.

Depending on your application, you can decide to create a global entity manager whose life cycle is attached to the life of the application itself. That is a single entity manager for the entire life of the application. In this cases, your context will be created and destroyed with your entity manager.

Or, you could create an entity manager per conversation (i.e. transaction) with your application user. The scope, in this case, is determined by you, but still, your context will be created and destroyed with your entity manager.



Related Topics



Leave a reply



Submit