Can I use one repository interface to make calls to multiple entity tables using Spring JPA? - spring-boot

I have a scenario where I need to fetch data from 20 tables in an Oracle database. I have 20 entity classes and I am using Spring JPA for getting data. I am using Simple Crud operation for getting data like
{
public interface Object1Repository extends CrudRepository<Object1, Long> {
List<Object1> findAll();
}
}
same for table2
{
public interface Object2Repository extends CrudRepository<Object2, Long> {
List<Object2> findAll();
}
}
and so on for table3, table4 etc...
So my question is do I need to create 20 such interface repositories to fetch data from database or is there a better way of doing it something like:
{
public interface CommonRepository extends CrudRepository<GenericObject, Long> {
List<Object1> findAll();
List<Object2> findAll();
List<Object3> findAll();
List<Object4> findAll();
...
}
}

You will have to create a repository interface for each entity, and move the logic of querying the 20 tables to your #Service component which will act as a "Business Service Facade". You can annotate your method with #Transactionl to if you want to query all together, or non if one query fails.

As it was mentioned, you'll have to create each repository for each entity.
But you can call all the tables in one request if you connect the entities between them using JPA relations: #OneToMany, #ManyToOne, #ManyToMany or #OneToOne

Related

How to avoid unwanted queries hibernate query data when import data from entity to DTO

I have some entities below
#Entity
#Table("processitem")
public class Processitem {
...
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="task")
public Task task;
#ManyToOne
#JoinColumn(name="user")
public User user;
//... and some more relationship to other
}
#Entity
#Table(name="task")
public class Task {
...
#OneToMany(mappedBy="task",cascade = CascadeType.ALL,orphanRemoval = true)
private Set<Processitem> processitem;
...
}
Now I import a List to List (I use a loop for to import data from entity to DTO), (around more 200 records) the hibernate execute a lots queries and performance is not good. Is there any solution to avoid that ? I tried using Entity Graph but it still doesn't improve (some time 2 queries is better 1 query with left join)
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 or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(Task.class)
interface TaskDto {
#IdMapping
Long getId();
String getName();
#Mapping(fetch = MULTISET)
Set<ProcessitemDto> getProcessitem();
}
#EntityView(Processitem.class)
public interface ProcessitemDto {
#IdMapping
Long getId();
#Mapping("user.name")
String getUserName();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
TaskDto task = entityViewManager.find(entityManager, TaskDto.class, id);
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
You can make use of the various fetching strategies provided by Blaze-Persistence Entity-Views but the best one is usually the MULTISET fetch strategy. Here you can read more about it: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#anchor-fetch-strategies

Spring Data JPA - findBy mapped object

In my legacy application, I have a country table, state table and a mapping table for country and state with few additional columns.
I have created an entity class like this.
class CountryStateMapping {
#Id
private long id;
private Long countryId;
#OneToOne
#JoinColumn(name="state_id")
private State state;
//getters seters
}
My repository.
public interface CountryStateMapping extends JpaRepository<CountryStateMapping, Long>{
Optional<CountryStateMapping> findByStateId(long stateId);
Optional<CountryStateMapping> findByState(State state);
}
I would like to check if the state exists in the mapping table. Both of the below approaches do not work.
countryStateMapping.findByStateId(long stateId)
countryStateMapping.findByState(State state)
What is the right way?
Its not the correct way i feel.The correct way for doing this will be
public interface CountryStateMappingRepository extends JpaRepository<CountryStateMapping, Long> {
Optional<CountryStateMapping> findByStateId(long stateId);
#Query("select s.something from State s" )
Optional<CountryStateMapping> findByState(State state);
}
This implies two things
By extending JpaRepository we get a bunch of generic CRUD methods to create, update, delete, and find
2.It allows Spring to scan the classpath for this interface and create a Spring bean for it.
Also you need some configuration.For that you need to create a configuration class to be used with your data source.You can find many examples to do the same and one such is https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa.
You can also use custom queries and simple queries using the #Query annotation.
Thanks
Try with an underscore for id like below;
public interface CountryStateMapping<CountryStateMapping, Long>{
Optional<CountryStateMapping> findByState_Id(long stateId);
Optional<CountryStateMapping> findByState(State state);
}

In Spring data JPA ,How to query data from a table without a repository for entity

Is it possible to fetch data from a table without creating a JPA repository for this specific table.
I need to do this as there are considerable number of entities which I have to do a simple query , it would be a waste to create repositories for each of them.
You can simply inject an EntityManager to any component:
#Component
class SomeComponent {
#PersistenceContext
private EntityManager entityManager;
public List<SomeEntity> findAllEntities() {
TypedQuery<SomeEntity> query = entityManager.createQuery("SELECT e FROM SomeEntity e", SomeEntity.class);
return query.getResultList();
}
}
Also, if your entities have the same superclass, you can use the same Repository for all of them, like described there.

Is this design of a Spring JPA DAO bad or improper?

I have been working to generalize the methods of the DAO for a project using Spring, JPA and Hibernate. However, I am still very much learning Spring, Java, and coding in general.
Is the below design bad or perfectly fine? Is there a better way to accomplish the same thing? Any advice would be greatly appreciated.
I have simplified the class:
#Repository
public class TestRepository
{
#PersistenceContext
private EntityManager entityManager;
public List<?> getListResults(Class<?> dtoClass, String sqlString)
{
List<?> returnList = null;
Query query = entityManager.createNativeQuery(sqlString, dtoClass);
try
{
returnList = (List<?>) query.getResultList();
}
catch (Exception e)
{
}
return returnList;
}
}
Spring Data JPA is the must convenient way in order to interact with your databases because it helps you to avoid the common mistakes that occurs when you try to configure your ORM mapping, entityManager, transacctionManager and all the rest of necessary components in order to establish a communication between your entity domains and your database.
For example you have a pojo like this:
#Entity
public class Item {
#Id
private Long id;
......
}
You can create an interface in order to get or put information to the item repository like this:
public interface ItemRepository extends from JpaRepository<Item,Long>{}
When you need to save the Item just #Autowired the ItemRepository, this is the must important part because the previous interface that is created without methods now exposes ready-to-work methods that will interact with your database, this is the abstraction level that makes Spring Data JPA very useful:
#Autowired
ItemRepository itemRepo
public void createItem(){
Item item = new Item();
itemRepo.save(item);
//or you can get information
List<Item> itemList = itemRepo.findAll();
}
More information in Spring Data JPA Documentation
How about using Spring Data Repositories?
#Repository
public interface SomethingRepository extends JpaRepository<Something, Long> {
}
That way you get lots of methods without having to manually write your SQL query as a string, you retain type safety and you can leverage the power of JPA queries and dynamic proxies that do this whole SQL business for you.

#NamedQuery override findAll in Spring Data Rest JpaRepository

Is there a way to override the findAll query executed by Spring Data Rest?
I need a way of filtering the results based on some specific criteria and it seems that using a #NamedQuery should be along the lines of what I'm looking for so I setup a test.
#Entity
#Table(name = "users")
#NamedQueries({
#NamedQuery(name = "User.findAll", query="SELECT u FROM User u WHERE u.username = 'test'"),
#NamedQuery(name = "User.findNameEqualsTest", query="SELECT u FROM User u WHERE u.username = 'test'")
})
public class User implements Serializable, Identifiable<Long> { }
With this in place I would expect SDR to utilize my findAll() query (returning 1 result) but instead it executes the same old findAll logic (returning all results).
In my Repository I added:
#Repository
#RestResource(path = "users", rel = "users")
public interface UserJpaRepository extends JpaRepository<User, Long> {
public Page<User> findNameEqualsTest(Pageable pageable);
}
and in this case it DOES pick up the provided #NamedQuery. So...
How should I go about overriding the default findAll() logic? I need to actually construct a complex set of criteria and apply it to the result set.
In the upcoming version 1.5 (an RC is available in our milestone repositories) of Spring Data JPA you can simply redeclare the method in your repository interface and annotate it with #Query so that the execution as query method is triggered. This will then cause the named query to be looked up just as you're already used to from query methods:
interface UserJpaRepository extends PagingAndSortingRepository<User, Long> {
#Query
List<User> findAll();
Page<User> findNameEqualsTest(Pageable pageable);
}
A few notes on your repository declaration:
You don't need to annotate the interface with #Repository. That annotation doesn't have any effect at all here.
Your #RestResource annotation configures the exporter in a way that will be the default anyway in Spring Data REST 2.0 (also in RC already). Ging forward, prefer #RestRepositoryResource, but as I said: the pluralization will be the default anyway.
We generally don't recommend to extend the store specific interfaces but rather use CrudRepository or PagingAndSortingRepository.
Yes, you can create your Implementation of your Repository interface, there is acouple section in
http://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/html/repositories.html#repositories.custom-implementations
Repository
#Repository
public interface PagLogRepository extends JpaRepository<PagLogEntity, Long>, PagLogCustomRepository {
Custom Interface
public interface PagLogCustomRepository {
PagLogEntity save(SalesForceForm salesForceForm) throws ResourceNotFoundException;
Custom implementation
public class PagLogRepositoryImpl implements PagLogCustomRepository {
#Override
public PagLogEntity save(final SalesForceForm salesForceForm) throws ResourceNotFoundException {
query = emEntityManager.createNamedQuery("findItemFileByDenormalizedSku", ItemFileEntity.class);
query.setParameter("skuValue", rawSku);
Instead of override save make it with findAll, then you can create complex customization

Resources