Creating an instance of Entity in Spring without any Spring interaction - java

In my project based on spring-data-rest I have some classes annotated with the #Entity annotation.
#Entity
#Table(name = "my_table)
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class MyTable extends BaseTableEntity {
private String name;
private String description;
}
Now I am not quite sure as to how Spring handles creation of new instances of classes annotated with that annotation. I needed to create an object of such an Entity class making sure that no database operations takes place.
To make it clear, say I do MyTable table = new MyTable() in a POJO class. Can I be sure that Spring with the help of Hibernate/JPA won't create records in my database. What if I do the same in a #Component class instead of a POJO.

Creating a new entity with new keyword does not make any insert into db. The entity is in detached state. You would have to pass this entity to reporitory.save or entityManager.persist or entityManager.merge... But as long persist is not invoked (directly or indirectly), it's a regular pojo without a representation in database.

Related

Converting an #Entity to a projection interface manually

So I've been using Spring Data Repositories most of the time. But I've reached a use-case where I cannot use my Spring Repository to retrieve the entity that I need to return to the client.
So I have my class ResourceEntity which is a Spring Data Entity. And I'd like to return this entity as a ResourceProjectioninterface.
#Getter
#Setter
#NoArgsConstructor
#Entity
public class ResourceEntity{
private Long id;
private String name;
private String anotherFieldThatIsNotInTheProjection;
}
public interface ResourceProjection {
Long getId();
String getName();
}
Usually with a Spring Repository, I'd define something like that :
public interface ResourceRepository extends PagingAndSortingRepository<ResourceEntity, Long> {
Optional<ResourceProjection> getById(Long id);
}
In this case I can't use the "automatic proxy" generated by Spring Data to automatically implement my projection with the entity's data.
So my question is : Is there a way to "manually" convert the entity to the projection ?
Another solution I thought of is returning the entity and using Jackson annotations like #JsonIgnore to prevent some of my data to be returned, but that is not optimal with the way my code was written.
Otherwise I can always create a DTO class that will fill up with the data from the Entity. But as I have already created my projection for other purposes, I would like avoid creating a second "DTO".
You can do the projection programmatically in this way:
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
//...
resourceEntity = //find resource
ProjectionFactory pf = new SpelAwareProxyProjectionFactory();
ResourceProjection rp = pf.createProjection(ResourceProjection.class, resourceEntity)
This is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.
A mapping for your model could look as simple as the following
#EntityView(ResourceEntity.class)
interface ResourceProjection {
#IdMapping
Long getId();
String getName();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
ResourceProjection dto = entityViewManager.find(entityManager, ResourceProjection.class, id);
But the Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Implementing interface projection using native sql query
1. OurResourceEntity.java class
#Getter
#Setter
#NoArgsConstructor
#Entity
public class ResourceEntity{
private Long id;
private String name;
}
2. Creating projection Interface name ProjectedResource.java, which maps data collected by the SQL query from repository layer method
public interface ProjectedResource {
Long getId();
String getName();
String getAnotherProperty();
}
3. Creating Repository layer method: getProjectedResources()
We are considering the database table name is resource.
We are only fetching id and name here.But using interface projection we can change the properties name according to our desire.
#Query(name="select id, name, anotherProperty from resource", nativeQuery=true)
List<ProjectedResource> getProjectedResources();
Hope the issue will be resolved!

What is the difference between #Entity and #Repository annotations?

I am new in spring and hibernate and I got these two annotations #Entity and #Repository used for DAO class. As both the annotations are used for the DAO class. Then, what is the difference and when to use one of them.
The #Entity class is the model and the #Repository is the layer that helps you to extract the data from database. For example :
#Entity
public class Student {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(unique=true)
private String name;
//getters - setters
}
And the repository:
#Repository
public interface StudentRepository extends CrudRepository<Student,Long> {
public Student findByName(String name);
}
The basic CRUD operations are already provided by CrudRepository interface so there is no need to implement them again. You can use them in a Service class like this:
#Service
public class StudentServiceImpl implements StudentService {
#Autowired
public StudentRepository studentRepository;
#Override
public List<Student> findAll()
{
return studentRepository.findAll():
}
#Override
public Student findByName(String name)
{
return studentRepository.findByName(name);
}
}
And in case you want to make custom queries like get a student by name, jpa hibernate is very smart and helps you to only define the method in the #Repository annotated interface and there is no need of any implementations. BUT there is a rule here if you want to make it work. Hibernate will look after method name like this : public Student findByName(String name); the find and Student return type tells hibernate that it have to look for a Student, byName will tell that it have to query the database for a Student with a specific name. (The Name keyword is actually the entity attribute with capital letter ! )
But of course, if you need some more complex queries, there is the #Query annotation that will help you with that :) .
#Entity annotation defines that a class can be mapped to a table, it is just a marker, like for example Serializable interface.
Entity is an object representing (usually) a row in a db.
#Repository annotation defines CRUD operation on table.
It is very like DAO pattern to fetch and save entities from/to storage - it represents db table.
#Entity
Let's say we have a POJO called Student which represents the data of a student and we would like to store it in the database.
public class Student {
// fields, getters and setters
}
In order to do this, we should define an entity so that JPA is aware of it.
So let's define it by making use of the #Entity annotation. We must specify this annotation at the class level.
#Entity
public class Student {
// fields, getters and setters
}
In most typical applications, we have distinct layers like data access, presentation, service, business, etc.
And, in each layer, we have various beans. Simply put, to detect them automatically, Spring uses classpath scanning annotations.
#Repository
#Repository annotates classes at the persistence layer, which will act as a database repository. #Repository’s job is to catch persistence specific exceptions and rethrow them as one of Spring’s unified unchecked exception.
to sum up #Entity is part of JPA Java Persistence API specification used mapping between a java POJO and an entity in relational database world and #Repository is a Spring stereotype used to annotate POJO beans than their jobs is database manipulation operations

how to pass schema dynamically in the entity when the server is already running

i need to pass the schema name dynamically to the entity
#Entity
#Table(name = "customer_table" schema="${dynamicSchemaName}")
#JsonIgnoreProperties
public class Customer implements Serializable {
//....
}
how can i replace ${dynamicSchemaName} with the schema that will be picked by the code where this entity is called?
The simple answer is that you can't. Although there are hacks and ways to inject dynamic data into an annotation, that doesn't exist for Hibernate. Annotations are defined at compile time and read at run time.

How to prevent Spring JPA Entities from becoming optional when saving to CRUDRepository?

I was trying to learn Spring Framework and ran into a problem with saving entities into CRUD Repository. I had few Entities with automatic numeric ID generation and they work just fine, but then I tried to make a class with String being a primary key just like this:
#Entity
#Table(name = "USERS")
#Builder
public class User {
#Id
#Column(name = "USER_NAME", nullable = false)
#Getter #Setter
private String name;
#Column(name = "USER_PASS", nullable = false)
#Getter #Setter
private String pass;
}
First I was getting exceptions about this class not having a default constructor:
org.springframework.orm.jpa.JpaSystemException: No default constructor for entity: : com.company.Model.User; nested exception is org.hibernate.InstantiationException: No default constructor for entity: : com.company.Model.User
Already weird, but still I decided to change #Builder annotation into 2 constructors, one with both arguments and second with none. I tried to save the entity instance into CRUD Repository userDAO (which is nothing more than interface extending CRUDRepository) by the typical test:
User admin = new User("admin", "6aDcZ72k");
...
#Test
public void saveUserAndFindById() {
admin = userDAO.save(admin);
assertThat(userDAO.findById(admin.getName())).isEqualTo(admin);
}
The result was assertion failed because the saved entity had "Optional" type:
org.junit.ComparisonFailure:
Expected :com.company.Model.User#2c06b113
Actual :Optional[com.company.Model.User#2c06b113]
I know I'm doing something really wrong but can't figure this out. Or maybe there is a way to just prevent making it optional? There must be few other entities with the reference on this class, but these references obviously don't work because of the above issue.
First of all,jpa require the entity has a No Arguments Constructor cause it will create a instance first and then populate it.The easiest way is to add #NoArgumentsConstructor that offered by lombok on the entity class.
And then,Optional is used by spring data jpa in order to avoid NullPointException and in fact it be is useful actually.If you want to use the interface that Spring-data-jpa offered,then you have to use Optional too.You cloud look here for more info about Optional:link1,link2
By the way,I usually use it like:
ExampleEntity example=exampleRepository.findById(id).orElseThrow(()->new ExampleNotFoundException());
In this way,you dont need to deal with Optional or think about NullPointException.
or:
ExampleEntity example=exampleRepository.findById(id).orElse(null);
In this way if you cant find the target entity,then it will be null.So dont forget to check if the entity is null.
Hope it could help~~~
It is not your save(...) that is returning Optional but userDAO.findById(admin.getName(). According to the documentation, CrudReposiotry provides a findById() whose return type is Optional<T>.
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
Optional<T> findById(ID primaryKey);
}
If you do not want Optional as return type, You will need to provide your own method to do that. For example:
public interface PeronRepository extends CrudRepository<Person, String> {
Person findById(String personId);
}

JPA entity inheritance without additional tables

I am working on a Maven Java web project based on Spring, JPA and Hibernate.
One part of this project shall be reused in another very similar project and gets therefore extracted as Maven module. This service and the corresponding entity are annotated like this:
#Service
public class MessageService
#Entity
public class Message
Both projects have similar but slightly different UserEntities.
#Entity
public class TypeAUser
#Entity
public class TypeBUser
The Message Entity has #OneToMany relationship to one of the UserEntities in each project.
I thought about a generic UserEntity but want to avoid creating additional tables as well as tables with fields of the "other" project.
Any ideas are appreciated.
Best regards,
Stefan
If you don't want to create additional tables, then you might want to consider using SINGLE_TABLE strategy.
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class UserEntity {
...
}
#Entity
public class TypeAUser extends UserEntity {
...
}
#Entity
public class TypeBUser extends UserEntity {
...
}
Well, when talking about Inheritance in Hibernate, you have three options:
Table per concrete class with unions
Table per class hierarchy(Single Table Strategy)
Table per subclass
Since you want to achieve it with one table, I suggest using option 2.
You need just a User table, with a USER_TYPE column to discriminate the user types ( Can be a number, varchar2, etc)
Then you need to create a class User with the following annotations:
You can specify a DiscriminatorColumn if you want, otherwise Hibernate will default to '{className}_TYPE
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="USER_TYPE", discriminatorType=DiscriminatorType.STRING)
public class User { .... }
In your concrete class implementations you can specify a Discriminator value (or if you don't, hibernate will default it to the class name ('TypeAUser'/ 'TypeBUser')
#Entity
#DiscriminatorValue('A')
public class TypeAUser
#Entity
#DiscriminatorValue('B')
public class TypeBUser

Categories

Resources