I have two entities Customer and Animal, and I need to list the animals of a given customer, the animal entity receives the id of the customer I would like to list all the animals that have this id.
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "customerId", nullable = false)
private Customer customer;
You can use Spring Data JPA dependency which will make the task easy for you.
Add this dependency in your pom file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Assuming your Animal class looks like this:
#Entity
public class Animal {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#ManyToOne(cascade=CascadeType.MERGE)
private Customer customer;
//setters and getters
}
your repository class will look like this:
public interface AnimalRepository extends CrudRepository<Animal, Long> {
List<Animal> findByCustomer(Customer customer);
}
In your controller you should have an endpoint that receives the customerId.
That controller will call a service method, that receives the customerId and with that info call a repository method named findByCustomer (or something similar), which is the one that queries the database for the info.
The select will be something like:
select * from animals a where a.customerId = customerId
I recommend you to read about Spring Data JPA which is the tool that use Spring to make that db queries and repository implementation easier.
Related
#Entity
class Person{
private int id;
#OneToMany(mappedBy=owner)
private List<Pet> pets;
}
#Entity
class Pet{
private name;
private ZonedDateTime birthDate;
#ManyToOne
#JoinColumn(name="owner_id")
private Person owner;
}
I want to find all the persons and order them by their oldest pet birthday
The only way I can solve this is through #Formula , something like
#Entity
class Person{
private int id;
private List<Pet> pets;
#Formula("(SELECT p.birth_date FROM pet p WHERE p.owner_id = id order by p.birth_date ASC LIMIT 1)")
private ZonedDateTime oldestPetBirthday;
}
then
public List<Person> findPersonByOrderByOldestPetBirthdayAsc
But I don't want to touch raw sql, I am looking for something like
public List<Person> findPersonByOrderByPetsTop1OrderByBirthDateAsc
OR by using pageable something like:
PageRequest.of(page,pageSize,Sort.by(ASC, "pets.sort(BirthDateComparator).get(0)"))
is that possible?
Try to use #OrderBy annotation from #javax.persistence.OrderBy package on your one to many collection object.
#OrderBy("birthDate")
private List<Pet> pets;
Your solution with the formula is ok but suffers from some issues. Anyway, since you don't want to write SQL, you will have to use something like 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(Person.class)
public interface PersonDto {
#IdMapping
Long getId();
#Limit(limit = "1", order = "birthDate desc)
#Mapping("pets")
OldestPetDto getOldestPet();
#EntityView(Pet.class)
interface OldestPetDto {
#IdMapping
Long getId();
ZonedDateTime getBirthDate();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
PersonDto a = entityViewManager.find(entityManager, PersonDto.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
Page<PersonDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!
Also, you can add a Sort for oldestPet.birthDate and it will work just like you would like it to!
I've been doing research lately on inheritance strategies of JPA.I decided to develop a new project and I decided that the most suitable strategy for me in this project is JOINED.My Entity hierarchy is like this:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Account {
#Id
#GeneratedValue
private long id;
private String iban;
}
#Entity
public class DrawingAccount extends Account{
public String drawingInfo;
}
#Entity
public class SavingsAccount extends Account{
private String savingsInfo;
}
When I create a structure in this way, the database structure is created as I want. The common field (like IBAN) of subclasses is kept on the account table.Different fields on subclasses are kept in their own tables.But when I want to fetch only common fields ( like IBAN ) from database (SELECT * FROM ACCOUNT) it is sending a JOIN query to the tables of the subclasses for me.It's nice that it does this, but I only want to see the common areas.I only want the data for the ACCOUNT table in the database. Is there a way around this? I don't want it to send a JOIN query.There is nothing wrong with sending a JOIN, but in some cases like when i need this, it should send a join query. When I don't want it to send a join query, it should not send JOIN.How can I do it?
Is it possible to use JPA derived methods and query by example at the same time?
Let's imagine i have two entities like this:
#Entity
#Data
public class Person {
#Id
#GeneratedValue
Long id
String name;
String surname;
#OneToMany
List<Dog> dogs;
}
#Entity
#Data
public class Dog{
#Id
#GeneratedValue
Long id
String name;
}
I'd like to be able to do something like this (just an example):
Person p = new Person ();
p.setName("Mario");
personRepository.findDistinctByDogsIsNotNull(Example.of(p));
The Example.of(p) only works if i do findAll, but it doesn't work if i define inside the repository a method like this
private interface PersonRepository extends JpaRepository<Person, Long>{
List<Person> findDistinctByDogsIsNotNull(Example<Person> example)
}
The error it gives me is something like this:
Failed to create query for method public abstract java.util.List dev.cele.test.repository.PersonRepository.findDistinctByDogIsNotNull(org.springframework.data.domain.Example)! At least 1 parameter(s) provided but only 0 parameter(s) present in query.
So my question is: is it possible to do a query by example in a JPA derived query method?
And if it's not possible how can i create some sort of parametrizable query that also has a predetermined condition?
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.
I have a simple Invoice System where I need to create and update Invoices. I'm trying to use Spring Data Rest for that, but from what I get from the docs I really would end up doing a lot of calls to implement an update.
#Entity
class Article {
#Id
#GeneratedValue
Long ID;
#Basic
String name;
}
#Entity
class Invoice {
#Id
#GeneratedValue
Long ID;
#Basic
String customer;
#OneToMany(cascade=CascadeType.ALL)
List<InvoiceItem> items;
}
#Entity
class InvoiceItem {
#Id
#GeneratedValue
Long ID;
#Basic
double amount;
#ManyToOne
private Article article;
}
I'm using Spring Data Rest to expose this model to my web fronend via these Spring Data Rest/JPA Repositories
#RepositoryRestResource(collectionResourceRel = "articles", path = "articles")
interface ArticleJPARepository extends JpaRepository<Article, Long> {}
#RepositoryRestResource(collectionResourceRel = "invoices", path = "invoices")
interface InvoiceJPARepository extends JpaRepository<Invoice, Long> {}
#RepositoryRestResource(collectionResourceRel = "invoiceitems", path = "invoiceitems")
interface InvoiceItemJPARepository extends JpaRepository<InvoiceItem, Long> {}
So let's say I have an update form that looks like this:
where I can do several things:
Update Invoice customer
Change an Article of an existing InvoiceItem
Remove some of the InvoiceItems
Append a new InvoiceItem
From what I get from the Spring Rest Docs is that I need to make several calls now.
Update of the invoice customer I need to PUT /invoices/1
then update n the Article and amount in an InvoiceItem PUT n times PUT /invoiceitems/<x>/
Append m new InvoiceItems m times POST /invoiceitems then POST /invoices/1/items
Delete InvoiceItem 2 DELETE /invoiceitems/2 and then DELETE /invoices/1/items/<2>
Is there a simpler way to realise such an update with Spring Data Rest?