How annotation mapping is done in java persistence? - java

We use annotations for mapping the entity class with the database table by simply specifying #Entity and more like #Id, table joins and many things. I do not know how these entity variables are getting mapped with database table. Can anyone give a short description for understanding.
Thanks :)

Well the idea is to translate your objects and their connections with other objects into a relational database. These two ways of representing data (objects defined by classes and in tables in a database) are not directly compatible and that is where a so called Object Relational Mapper framework comes into play.
So a class like
class MyObject
{
private String name;
private int age;
private String password;
// Getters and setters
}
Will translate into a database table containing a column name which is of type varchar, age of type int and password of type varchar.
Annotations in Java simply add additional information (so called meta data) to your class definitions, which can be read by any other class (e.g. JavaDoc) and in the case of the Java Persistence API will be used by an ORM framework like Hibernate to read additional information you need to translate your object into the database (your database table needs a primary id and some information - like what type of a relation an object has to another - can't be automatically determined by just looking at your class definition).

Annotations are very well explained here:
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/

annotations are just metadata on a class, nothing magical. You can write your own annotations. Those annotations are given retention policies of runtime (which means you have access to that metadata at runtime). When you call persist etc the persistence provider iterates through the fields (java.lang.reflect.Field) in your class and checks what annotations are present to build up your SQL statement. Try writing your own annotation and doing something with it. It won't seem very magical after that.

in your case annotation working means mapping with tablename with entity class is look like as ....
#Entity
#Table(name = "CompanyUser")
public class CompanyUserCAB implements java.io.Serializable
{
private long companyUserID;
private int companyID;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "companyUserID")
public long getCompanyUserID()
{
return this.companyUserID;
}
public void setCompanyUserID(long companyUserID)
{
this.companyUserID = companyUserID;
}
#Column(name = "companyID")
public int getCompanyID()
{
return this.companyID;
}
public void setCompanyID(int companyID)
{
this.companyID = companyID;
}
}

Related

Can I directly map the data from an external source on it to persist on DB?

I am pretty new in Spring Data JPA and ORM in general. I have the following architectural doubt.
Lets consider this entity class:
#Entity // This tells Hibernate to make a table out of this class
public class Order {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column(name = "name")
private String fullName;
private String address;
private String product;
#Column(name = "order_date_time")
private String orderDate;
private Double quantity;
// getters, setters
}
This class is mapped on my order database table.
In my application data came from an Excel document that I parse via Apace POI and than I have to persist on the database.
My doubt is: can I directly use this entity class to map an Excel row using Apache POI in order to persist the Excel rows as order table records? Or is better to use another DTO class to read the rows from Excel and than use this DTO to set the field values of my entity class?
An entity class can contain a constructor using fields?
Can I directly use this entity class to map an Excel row using Apache
POI in order to persist the Excel rows as order table records?
Yes you can.
Or is better to use another DTO class to read the rows from Excel and
than use this DTO to set the field values of my entity class?
It's certainly common to have a DTO layer between the two, but it's not required so it's up to you.
An entity class can contain a constructor using fields?
Yes, but at least Hibernate wants a non-private default constructor as well, so remember to create a protected Order() {} (or any visibility modifier besides private) in addition to your parameterized constructor.
I'm not a heavy user of Apache POI, but I do know it's used to manipulate MS files.
So, here are my two cents, in your use case, you can just read it and map directly to the Entity class as it doesn't expose an API to the external world.
However, if you were building a REST/SOAP API, I recommend you put a DTO in between so you don't mistakenly expose things that shouldn't be exposed.
From architectural point of view better to have a DTO class and encapsulate some logic there.
class CsvOrder {
private String fullName;
private String address;
public CsvRecord(String[] record) {
fullName = get(record, FULLNAME_INDEX);
address = get(record, ADDRESS_INDEX);
}
public Order toOrder() {
Order result = new Order();
result.setFullName(fullName);
return result;
}
}
public static <T> T get(T[] arr, int index) {
final T notFound = null;
return index < size(arr) ? arr[index] : notFound;
}
public static <T> int size(T[] array) {
return array == null ? 0 : array.length;
}
You can put a static method toOrder() to OrderServiceMapper, if you want to totally decouple layers
class OrderServiceMapper {
public static Order toOrder(CsvOrder order) {
Order result = new Order();
result.setFullName(order.getFullName());
return result;
}
}
Also, use Integer in place of int for id. Better to use Long everywhere
// This tells Spring to add this class to Hibernate configuration during auto scan
#Entity
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
}

Using Index annotation on superclass with Hibernate

I have an abstract superclass which every Entity on my domain is a subclass of it.
Using DB schema generation, I want to create an Index for each Entity, on a field on the superclass, and without using the Table annotation on every subclass.
My superclass
#MappedSuperclass
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = SEQUENCE)
private Long surrogateId;
#Index(name="id_index") // Every subclass should inherit this index, with its own name
#Column(unique = true, updatable = false, nullable = false)
private UUID id = UUID.randomUUID();
An example of subclass
#Entity
public class Customer extends BaseEntity {
...
}
I tried so far:
use the Table annotation with #Index on the superclass, but Hibernate
doesn't seem to use that annotation if it is not marked with #Entity.
For example
#Table(indexes = {#Index(name="index_id", columnList = "id")})
No SQL statements are generated.
use the deprecated #Index annotation with a name "id_index", but only one index
is created on startup (the db raises an error that this index already
exists for other entities). Some generated SQL statements:
Hibernate: create index id_index on "customer" ("id")
Hibernate: create index id_index on "user" ("id")
2020-02-15 17:47:26,620 WARN o.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl - GenerationTarget encountered exception accepting command : Error executing DDL "create index id_index on "customer" ("id")" via JDBC Statement
org.postgresql.util.PSQLException: ERROR: relation "id_index" already exists
Any ideas on how to do this without too much code duplication?
Thanks
The only way I can see to do this - and it appears more trouble than it is worth to simply avoid placing an #Table annotation on each Entity - is to create a custom dialect and override the getIndexExporter() method:
public class MyPostgreSQLDialect extends PostgreSQLXXDialect{
#Override
public Exporter<Index> getIndexExporter() {
return new MyIndexExporter(this);
}
}
to return a customized Exporter, most likely extending org.hibernate.tool.schema.internal.StandardIndexExporter
public class MyIndexExporter extends StandardIndexExporter{
public MyIndexExporter(Dialect dialect){
super(dialect);
}
#Override
public String[] getSqlCreateStrings(Index index, Metadata metadata) {
//looks like you'd need to paste the whole code from superclass method
//and alter the index name accordingly
indexNameForCreation = index.getTable().getQualifiedTableName() +
"_" + index.getName();
//in the default implementation it is simply index.getName()
}
}
Alan Hay answer may work but it seems a bit of overengineering... So I decided to not use schema generation and use Liquibase instead, so I can have more control over the database.
Anyway, If anyone is having the same problem with schema generation, I tried with #Index (using eclipselink) and it worked, so this issue is only in Hibernate.

Spring Data JPA - bidirectional relation with infinite recursion

First, here are my entities.
Player :
#Entity
#JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class,
property="id")
public class Player {
// other fields
#ManyToOne
#JoinColumn(name = "pla_fk_n_teamId")
private Team team;
// methods
}
Team :
#Entity
#JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class,
property="id")
public class Team {
// other fields
#OneToMany(mappedBy = "team")
private List<Player> members;
// methods
}
As many topics already stated, you can avoid the StackOverflowExeption in your WebService in many ways with Jackson.
That's cool and all but JPA still constructs an entity with infinite recursion to another entity before the serialization. This is just ugly ans the request takes much longer. Check this screenshot : IntelliJ debugger
Is there a way to fix it ? Knowing that I want different results depending on the endpoint. Examples :
endpoint /teams/{id} => Team={id..., members=[Player={id..., team=null}]}
endpoint /members/{id} => Player={id..., team={id..., members=null}}
Thank you!
EDIT : maybe the question isn't very clear giving the answers I get so I'll try to be more precise.
I know that it is possible to prevent the infinite recursion either with Jackson (#JSONIgnore, #JsonManagedReference/#JSONBackReference etc.) or by doing some mapping into DTO. The problem I still see is this : both of the above are post-query processing. The object that Spring JPA returns will still be (for example) a Team, containing a list of players, containing a team, containing a list of players, etc. etc.
I would like to know if there is a way to tell JPA or the repository (or anything) to not bind entities within entities over and over again?
Here is how I handle this problem in my projects.
I used the concept of data transfer objects, implemented in two version: a full object and a light object.
I define a object containing the referenced entities as List as Dto (data transfer object that only holds serializable values) and I define a object without the referenced entities as Info.
A Info object only hold information about the very entity itself and not about relations.
Now when I deliver a Dto object over a REST API, I simply put Info objects for the references.
Let's assume I deliever a PlayerDto over GET /players/1:
public class PlayerDto{
private String playerName;
private String playercountry;
private TeamInfo;
}
Whereas the TeamInfo object looks like
public class TeamInfo {
private String teamName;
private String teamColor;
}
compared to a TeamDto
public class TeamDto{
private String teamName;
private String teamColor;
private List<PlayerInfo> players;
}
This avoids an endless serialization and also makes a logical end for your rest resources as other wise you should be able to GET /player/1/team/player/1/team
Additionally, the concept clearly separates the data layer from the client layer (in this case the REST API), as you don't pass the actually entity object to the interface. For this, you convert the actual entity inside your service layer to a Dto or Info. I use http://modelmapper.org/ for this, as it's super easy (one short method call).
Also I fetch all referenced entities lazily. My service method which gets the entity and converts it to the Dto there for runs inside of a transaction scope, which is good practice anyway.
Lazy fetching
To tell JPA to fetch a entity lazily, simply modify your relationship annotation by defining the fetch type. The default value for this is fetch = FetchType.EAGER which in your situation is problematic. That is why you should change it to fetch = FetchType.LAZY
public class TeamEntity {
#OneToMany(mappedBy = "team",fetch = FetchType.LAZY)
private List<PlayerEntity> members;
}
Likewise the Player
public class PlayerEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "pla_fk_n_teamId")
private TeamEntity team;
}
When calling your repository method from your service layer, it is important, that this is happening within a #Transactional scope, otherwise, you won't be able to get the lazily referenced entity. Which would look like this:
#Transactional(readOnly = true)
public TeamDto getTeamByName(String teamName){
TeamEntity entity= teamRepository.getTeamByName(teamName);
return modelMapper.map(entity,TeamDto.class);
}
In my case I realized I did not need a bidirectional (One To Many-Many To One) relationship.
This fixed my issue:
// Team Class:
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<Player> members = new HashSet<Player>();
// Player Class - These three lines removed:
// #ManyToOne
// #JoinColumn(name = "pla_fk_n_teamId")
// private Team team;
Project Lombok might also produce this issue. Try adding #ToString and #EqualsAndHashCode if you are using Lombok.
#Data
#Entity
#EqualsAndHashCode(exclude = { "members"}) // This,
#ToString(exclude = { "members"}) // and this
public class Team implements Serializable {
// ...
This is a nice guide on infinite recursion annotations https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
You can use #JsonIgnoreProperties annotation to avoid infinite loop, like this:
#JsonIgnoreProperties("members")
private Team team;
or like this:
#JsonIgnoreProperties("team")
private List<Player> members;
or both.

How to beautifully update a JPA entity in Spring Data?

So I have looked at various tutorials about JPA with Spring Data and this has been done different on many occasions and I am no quite sure what the correct approach is.
Assume there is the follwing entity:
package stackoverflowTest.dao;
import javax.persistence.*;
#Entity
#Table(name = "customers")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
public Customer(String name) {
this.name = name;
}
public Customer() {
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
We also have a DTO which is retrieved in the service layer and then handed to the controller/client side.
package stackoverflowTest.dto;
public class CustomerDto {
private long id;
private String name;
public CustomerDto(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
So now assume the Customer wants to change his name in the webui - then there will be some controller action, where there will be the updated DTO with the old ID and the new name.
Now I have to save this updated DTO to the database.
Unluckily currently there is no way to update an existing customer (except than deleting the entry in the DB and creating a new Cusomter with a new auto-generated id)
However as this is not feasible (especially considering such an entity could have hundreds of relations potentially) - so there come 2 straight forward solutions to my mind:
make a setter for the id in the Customer class - and thus allow setting of the id and then save the Customer object via the corresponding repository.
or
add the id field to the constructor and whenever you want to update a customer you always create a new object with the old id, but the new values for the other fields (in this case only the name)
So my question is wether there is a general rule how to do this?
Any maybe what the drawbacks of the 2 methods I explained are?
Even better then #Tanjim Rahman answer you can using Spring Data JPA use the method T getOne(ID id)
Customer customerToUpdate = customerRepository.getOne(id);
customerToUpdate.setName(customerDto.getName);
customerRepository.save(customerToUpdate);
Is's better because getOne(ID id) gets you only a reference (proxy) object and does not fetch it from the DB. On this reference you can set what you want and on save() it will do just an SQL UPDATE statement like you expect it. In comparsion when you call find() like in #Tanjim Rahmans answer spring data JPA will do an SQL SELECT to physically fetch the entity from the DB, which you dont need, when you are just updating.
In Spring Data you simply define an update query if you have the ID
#Repository
public interface CustomerRepository extends JpaRepository<Customer , Long> {
#Query("update Customer c set c.name = :name WHERE c.id = :customerId")
void setCustomerName(#Param("customerId") Long id, #Param("name") String name);
}
Some solutions claim to use Spring data and do JPA oldschool (even in a manner with lost updates) instead.
Simple JPA update..
Customer customer = em.find(id, Customer.class); //Consider em as JPA EntityManager
customer.setName(customerDto.getName);
em.merge(customer);
This is more an object initialzation question more than a jpa question, both methods work and you can have both of them at the same time , usually if the data member value is ready before the instantiation you use the constructor parameters, if this value could be updated after the instantiation you should have a setter.
If you need to work with DTOs rather than entities directly then you should retrieve the existing Customer instance and map the updated fields from the DTO to that.
Customer entity = //load from DB
//map fields from DTO to entity
So now assume the Customer wants to change his name in the webui -
then there will be some controller action, where there will be the
updated DTO with the old ID and the new name.
Normally, you have the following workflow:
User requests his data from server and obtains them in UI;
User corrects his data and sends it back to server with already present ID;
On server you obtain DTO with updated data by user, find it in DB by ID (otherwise throw exception) and transform DTO -> Entity with all given data, foreign keys, etc...
Then you just merge it, or if using Spring Data invoke save(), which in turn will merge it (see this thread);
P.S. This operation will inevitably issue 2 queries: select and update. Again, 2 queries, even if you wanna update a single field. However, if you utilize Hibernate's proprietary #DynamicUpdate annotation on top of entity class, it will help you not to include into update statement all the fields, but only those that actually changed.
P.S. If you do not wanna pay for first select statement and prefer to use Spring Data's #Modifying query, be prepared to lose L2C cache region related to modifiable entity; even worse situation with native update queries (see this thread) and also of course be prepared to write those queries manually, test them and support them in the future.
I have encountered this issue!
Luckily, I determine 2 ways and understand some things but the rest is not clear.
Hope someone discuss or support if you know.
Use RepositoryExtendJPA.save(entity). Example:
List<Person> person = this.PersonRepository.findById(0)
person.setName("Neo");
This.PersonReository.save(person);
this block code updated new name for record which has id = 0;
Use #Transactional from javax or spring framework. Let put #Transactional upon your class or specified function, both are ok. I read at somewhere that this annotation do a "commit" action at the end your function flow. So, every things you modified at entity would be updated to database.
There is a method in JpaRepository
getOne
It is deprecated at the moment in favor of
getById
So correct approach would be
Customer customerToUpdate = customerRepository.getById(id);
customerToUpdate.setName(customerDto.getName);
customerRepository.save(customerToUpdate);

How to know the ID (#GeneratedValue) of a POJO at runtime

I have a form to fill a POJO called Father. Inside it, I have a FotoFather field.
When I save a new Father, I save automatically the object FotoFather (with Hibernate ORM pattern).
FotoFather.fotoNaturalUrl must be filled with the value of Father.id and here is the problem!
When i'm saving Father on the db, of course I still haven't Father.id value to fill FotoFather.fotoNaturalUrl. How can I solve this problem?
Thank you
#Entity
#Table(name = "father")
public class Father implements Serializable{
...
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
...
#OneToOne(targetEntity = FotoFather.class, fetch = FetchType.EAGER)
#JoinColumn(name = "fotoFather", referencedColumnName = "id")
#Cascade(CascadeType.ALL)
private FotoFather fotoFather;
}
FotoFather.class
#Entity
#Table(name = "foto_father")
public class FotoFather.class{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
...
#Column(name = "foto_natural_url")
private String fotoNaturalUrl;
...
}
If you simply need the complete URL for some application-specific purpose, I would likely err on the side of not trying to store the URL with the ID at all and instead rely on a transient method.
public class FotoFather {
#Transient
public String getNaturalUrl() {
if(fotoNaturalUrl != null && fotoNaturalUrl.trim().length > 0) {
return String.format("%s?id=%d", fotoNaturalUrl, id);
}
return "";
}
}
In fact, decomposing your URLs even more into their minimalist variable components and only storing those in separate columns can go along way in technical debt, particularly if the URL changes. This way the base URL could be application-configurable and the variable aspects that control the final URL endpoint are all you store.
But if you must know the ID ahead of time (or as in a recent case of mine, keep identifiers sequential without loosing a single value), you need to approach this where FotoFather identifiers are generated prior to persisting the entity, thus they are not #GeneratedValues.
In order to avoid issues with collisions at insertion, we have a sequence service class that exposes support for fetching the next sequence value by name. The sequence table row is locked at read and updated at commit time. This prevents multiple sessions from concurrency issues with the same sequence, prevents gaps in the range and allows for knowing identifiers ahead of time.
#Transactional
public void save(Father father) {
Assert.isNotNull(father, "Father cannot be null.");
Assert.isNotNull(father.getFotoFather(), "FotoFather cannot be null.");
if(father.getFotoFather().getId() == null) {
// joins existing transaction or errors if one doesn't exist
// when sequenceService is invoked.
Long id = sequenceService.getNextSequence("FOTOFATHER");
// updates the fotofather's id
father.getFotoFather().setId(id);
}
// save.
fatherRepository.save(father);
}
I think you can do be registering an #PostPersist callback on your Father class. As the JPA spec notes:
The PostPersist and PostRemove callback methods are invoked for an
entity after the entity has been made persistent or removed. These
callbacks will also be invoked on all entities to which these
operations are cascaded. The PostPersist and PostRemove methods will
be invoked after the database insert and delete operations
respectively. These database operations may occur directly after the
persist, merge, or remove operations have been invoked or they may
occur directly after a flush operation has occurred (which may be at
the end of the transaction). Generated primary key values are
available in the PostPersist method.
So, the callback should be called immediately after the Father instance is written to the database and before the FotoFather instance is written.
public class Father(){
#PostPersist
public void updateFotoFather(){
fotofather.setNaturalUrl("/xyz/" + id);
}
}

Categories

Resources