Spring data join mysql entity with collection mongodb - spring

i m doing a project with spring data. I have two table in my schema:
Hu
Movement: this table must contain each movement of hu. In production this table will have a lot of record so i will put the movement data on mongodb databale.
I've read that it is possible to use more datasource. But it is possible to use a mysql datasource and a mongodb datasource? If yes is possible to link HU to movement ( a join ) ? Movement collection have hu_id column.

yes it is possible to use two datasources one is SQL and the other one is NOSQL.
But I feel linking between two entities is not possible and it doesnt sound right.
Anyway, I have tried this approach where
Entity1.java :(SQL entity)
#Entity
#Table(name="ENTITY1")
public class Entity1 implements Serializable{
#Id
private long id;
}
Entity2.java :(NOSQL entity)
#Document(collection="test")
public class Entity2 implements Serializable{
#org.springframework.data.annotation.Id
private long Id;
//storing reference of entity1
#Field("Entity1REF")
private long entity1Id;
}
Entity1Repository :
public interface Entity1Repository extends JpaRepository<Entity1, Long> ()
Entity2Repository :
public interface Entity2Repository extends MongoRepository<Entity2, Long>{
While performing CRUD operations on the entity:
Make use of appropriate repos to perform.
#Autowired
private Entity1Repository entity1Rep;
#Autowired
private Entity2Repository entity2Rep;
public void init(){
Entity1 en1=new Entity1(100);
en1=entity1Rep.save(en1);
Entity2 en2=new Entity2(1000,en1.getId());
entity2Rep.save(en2);
}
Please go through this project tried :
https://github.com/BarathArivazhagan/Spring-MongoDB-Samples/tree/tree/Spring-Data-Mongo-SQL

Related

Designing one-to-one and one-to-many relationships in Spring Data R2DBC

I am exploring possible ideas when it comes to designing the one-to-one and one-to-many relationships while using Spring Data R2DBC.
As Spring Data R2DBC still do not support relationships natively there is still a need to handle those on our own (unlike Spring Data JDBC).
What I would imagine that when it comes to one-to-one mapping, the implementation could look like this:
#Table("account")
public class Account {
#Id
private Long id;
#Transient // one-to-one
private Address address;
}
#Table("address")
public class Address {
#Id
private Integer id;
}
while the database schema would be defined as follows:
--address
CREATE TABLE address
(
id SERIAL PRIMARY KEY
)
--account
CREATE TABLE account
(
id SERIAL PRIMARY KEY,
address_id INTEGER REFERENCES address(id)
)
As the Account object is my aggregate root what I would imagine is that I am supposed to load the Address object with it following the advice of Jens Schaduer:
An aggregate is a cluster of objects that form a unit, which should
always be consistent. Also, it should always get persisted (and
loaded) together.
source: Spring Data JDBC, References, and Aggregates
This leads me to thinking that in case of one-to-one relationships like this one I in fact should have my Account entity defined like this:
#Table("account")
public class Account {
#Id
private Long id;
#Transient // one-to-one
private Address address;
#Column("address_id")
private Integer addressId;
}
and later on to recreate the full Account aggregate entity with an Address I would write something like:
#Service
public class AccountServiceImpl implements AccountService {
private final AccountRepository accountRepository;
private final AddressRepository addressRepository;
public AccountServiceImpl(AccountRepository accountRepository,
AddressRepository addressRepository) {
this.accountRepository = accountRepository;
this.addressRepository = addressRepository;
}
#Override
public Mono<Account> loadAccount(Integer id) {
return accountRepository.getAccountById(id)
.flatMap(account ->
Mono.just(account)
.zipWith(addressRepository.getAddressByAccountId(account.getAddressId()))
.map(result -> {
result.getT1().setAddress(result.getT2());
return result.getT1();
})
);
}
}
If that is not the case, how else should I handle one-to-one relationships while using Spring Data R2DBC?
I think your approach is reasonable. There are just a couple of nitpicks:
Do you need the flatMap -> Mono.just ? Can't you just use map directly?
I wouldn't consider this a service, but a repository (it's just not implemented by Spring Data directly.
You might be able to that code in a after load callback.

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);
}

how to write the JpaRepository for tables which has composite keys

Please refer attached screenshot to understand the table structure.
Empd_Id is the primary key in 'Employee' table which in turn becomes as a part of composite key along with 'product_id' in table called 'product'.
Any employee can have multiple products so in that case it becomes 'One-to-Many' relationship between 'Employee-Product' tables. Now I'm confused whether I need to write just 1 JpaRepository interface i.e. for employee or 2 JpaRepository interfaces (1 for Employee and another for Product). My gut feeling is just 1 interface for Employee table but how???
Following is my code snippet:-
1st JPA repository interface
public interface MyRepository extends JpaRepository<Product, EmpProd> {
}
Entity:-
#Entity
#Table(name="product")
public class Product{
#EmbeddedId
private EmpProd empProd;
#Column(name="product_name")
private String commerceUserId;
#Column(name="description")
private String description;
For composite keys:-
#Embeddable
public class EmpProd implements Serializable{
private static final long serialVersionUID = 1L;
#NotNull
#Column(name="emp_id")
private String empId;
#NotNull
#Column(name="product_id")
private String productId;
2nd Jpa repository interface
public interface MyMainDataRepository extends JpaRepository<Employee, String> {
}
Entity class:-
#Entity
#Table(name="employee")
public class Employee{
#Id
#NotNull
#Column(name="emp_id")
private String empId;
#Column(name="first_name")
private String firstName;
Though, I have written 2 separate JPA repositories, I strongly believe there will be need for just 1, the main one i.e.
public interface MyMainDataRepository extends JpaRepository {
}
But I do not know to related both entity classes and fetch data from using single Jpa repository as I'm new to Spring Data JPA. I would really appreciate if someone can help me here. Thanks
The two entities Product and Employee don't have any connection as far as JPA is concerned. Therefore you can't access both through a single repository.
If for example, Product would have an actual reference to an Employee you could use a ProductRepository to load Products and navigate from there to the referenced Employees.
But even if that might be feasible, I'd guess that Product and Employee should be considered different aggregates and therefore, should have their own repository each. See Are you supposed to have one repository per table in JPA? for more information on that question.
Given the entities, your repositories look just fine. Note that the entities do look atypical due to the use of String productId instead of Product product.
If you wanted to fetch the employee details, you need the following interface,
public interface MyMainDataRepository extends JpaRepository<Employee, String> {
}
If you wanted to fetch the product details, you need the following interface,
public interface MyRepository extends JpaRepository<Product, EmpProd> {
}
The employee is related to product table, the iteration happens via product and related employees. From this, you can not access the employee table directly and retrieve the employee results from MyRepository interface.

Get entity property with Spring JPA

I'm using Spring JPA in my DAO layer. I have an entity Projet having inside an entity property Client:
Project.java
#Entity
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int projetId;
private String libelle;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="client_id")
private Client client;
// ... constructors, getters & setters
}
Client.java
#Entity
public class Client {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int clientId;
private String denomination;
// ... constructors, getters & setters
}
in my DAO interface I have the following specifications:
ProjetDao.java
#Repository
#Transactional
public interface ProjetDao extends CrudRepository<Projet, Integer> {
#Transactional
public Projet findByLibelle(String libelle);
#Transactional
public Projet findByProjetId(int projetId);
}
My question is: How can I specify in my DAO interface a method that will return all clients distinct in List<Client>?
From the documentation and JIRA:
List<Project> findAllDistinctBy();
The query builder mechanism built into Spring Data repository infrastructure is useful for building constraining queries over entities of the repository. The mechanism strips the prefixes find…By, read…By, query…By, count…By, and get…By from the method and starts parsing the rest of it. The introducing clause can contain further expressions such as a Distinct to set a distinct flag on the query to be created. However, the first By acts as delimiter to indicate the start of the actual criteria. At a very basic level you can define conditions on entity properties and concatenate them with And and Or.
You are dealing with a one-to-one relationship, in this case I guess the list that you need is not really related to specific project, you just want a distinct list of clients.
You will need to create another repository (ClientRepository) for the Client entity and add a findAllDistinct method in this repository.

Hibernate and JPA always load referenced tables

I am working with Hibernate 4+ Spring MVC + Spring Data with JPA annotations:
#Entity
public class ClassOne implements Serializable{
......
#OneToMany(mappedBy = "mapper", fetch=FetchType.LAZY)
private Set<ClassTwo> element = new HashSet<ClassTwo>(0);
//more fields
//getters and setters
//equals and hashcode
}
#Entity
public class ClassTwo implements Serializable{
......
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "CEN_CEN_CODIGO", nullable = false)
private ClassOne classOne;
//more fields
//getters and setters
//equals and hashcode
}
public interface ClassOneRepository extends CrudRepository<ClassOne, Long> {
#Override
#Query("select c from ClassOne c")
public List<ClassOne> findAll();
}
#Service
public class ClassOneService {
#Autowired
private ClassOneRepository classOneRepository;
#Transactional(readOnly=true)
public List<ClassOne> findAll() {
return classOneRepository.findAll();
}
}
And finally I call thie service from my #Controller
#Autowired
ClassOneService classOneService;
I expect results ONLY from ClassOne but retrieving the JOIN values with ClassTwo and all the database tree associate. Is it possible to get only values for ONE table using this schema? Is it a cache problem or Fetching not LAZY?
EDIT: I added the relatioship between two classes
Thank you
You must have the following anotation above your Set<ClassTwo> or its getter:
#OneToMany(fetch = FetchType.LAZY, ...)
See http://docs.oracle.com/javaee/7/api/javax/persistence/OneToMany.html#fetch()
It seems to be that simple "SELECT *" JPA query returns all eagerly fetched fields for the entity.
Please refer to: JPA - Force Lazy loading for only a given query
and http://forcedotcom.github.io/java-sdk/jpa-queries.
So my solution would be to use SessionFactory to get current session and then use "classic" method
return getCurrentSession().createCriteria(persistentClass).list();
Another possible way is to create let's say a POJO object without Set which uses the same table as ClassOne.
I've just added #Lazy for each #ManyToOne and #OneToMany relationship. It seems that Spring Data needs Spring annotations but I supposed that just was necessary to add fetch = FetchType.LAZY. No more Eager behaviours ;).
Thanks for your responses

Resources