I am developing an application that allows managing candidates in a company, for that I use spring-boot, in order to select the employees who master such a technology (Techno) I used a request JPQL.
So, How can I find a candidate by techno?
In my project I used this code:
1 - the class candidat.java
#Entity
public class Candidat {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "candidat_id")
private int id;
private String nom;
private String prenom;
private String ville;
private int numTel;
private String mail;
private String pseudo;
private String roleCible;
private String typeContrat;
private String villeRecherchee;
#OneToMany(mappedBy="candidat")
private List<Techno> techno;
#Temporal(TemporalType.DATE)
private Date date;
#OneToMany
private List<SecteurActivites> secteurActivites;
public Candidat() {
// TODO Auto-generated constructor stub
}
2- the class Techno.java
#Entity
public class Techno {
#Id
#GeneratedValue
#Column(name = "techno_id")
private int id ;
private String nomTechno;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "candidat_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Candidat candidat;
public Techno() {
// TODO Auto-generated constructor stub
}
/**
* #param nomTechno
* #param candidat
*/
public Techno(String nomTechno, Candidat candidat) {
super();
this.nomTechno = nomTechno;
this.candidat = candidat;
}
3- My CandidatController
#GetMapping(value = "/GetAllCandidats/{nomTechno}")
public List<Candidat> afficherCandidat(#PathVariable ("nomTechno") String nomTechno){
return candidatdao.findByTechno(nomTechno);
}
4- the repository:
#Repository
public interface CandidatDao extends JpaRepository <Candidat, String>{
List<Candidat> findByDate(Date date);
#Query("SELECT DISTINCT e FROM Candidat e INNER JOIN e.Techno t")
List<Candidat> findByTechno(String nomTechno);
}
5- app.properties
server.port= 9090
spring.jpa.show-sql = true
spring.datasource.url= jdbc:mysql://localhost:3306/database
spring.datasource.username=??
spring.datasource.password=??
spring.jpa.hibernate.ddl-auto=update
The result in console is:
"Validation failed for query for method public abstract java.util.List com.avatar.dao.CandidatDao.findByTechno(java.lang.String)!"
You can declare the following method into your JpaRepository (also remove the #Query, it is not needed).
List<Candidat> findDistinctByTechnoNomTechno(String nomTechno);
Also in Techno.java you should add the #Column annotation and map it with the DB schema.
I am not sure if you have pasted incomplete code of your entities on purpose. If not your entities are not correct. You should create setters/getters as the following
private String nomTechno;
#Column(name = "NOM_TECHNO")
public String getNomTechno() {
return nomTechno;
}
public void setNomTechno(String nomTechno){
this.nomTechno = nomTechno;
}
Do the above for all variables in your entities.
You do not need to add explicit #Query for this, Spring data can formulate a query if you have right method names
Instead of
#Query("SELECT DISTINCT e FROM Candidat e INNER JOIN e.Techno t")
List<Candidat> findByTechno(String nomTechno);
Try this
List<Candidat> findDistinctByTechno_NomTechno(String nomTechno);
Related
I'm trying to create findBy JpaRepo it's about returning only the data where isDeleted attribute is false.
this is my Service :
public List<Customer> getAllCustomers() {
List<Customer> customers = cutomerRepository.findByIsDeletedFalse();
return customers;
}
and this is my Controller :
#GetMapping("/viewList")
#CrossOrigin("http://localhost:4200/")
public ResponseEntity<List<Customer>> getAllCustomers() {
List<Customer> customers = new ArrayList<>();
customers = customerService.getAllCustomers();
if (customers.isEmpty()) {
LOGGER.error("no content ");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
LOGGER.info("calling list of customers");
return new ResponseEntity<>(customers, HttpStatus.OK);
}
and this is customer model :
public class Customer {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name = "serial_number")
private long serialNumber;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "email")
private String email;
#Column(name = "mobile_number")
private String mobileNumber;
#Column(name = "is_deleted")
private boolean isDeleted;
}
but when I run it in postman it's not working and return an error :
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not
exist: boolean = integer Hint: No operator matches the given name
and argument types. You might need to add explicit type casts.
Position: 315
How could I solve this issue?
Looks like the name for your query isn't created right.
However, in this case, the usage of #Query will be much clearer.
Code snippet:
public interface CustomerRepo extends JpaRepository<Customer, Integer> {
List<Customer> findAllByIsDeletedIsFalse();
#Query("from Customer c where c.isDeleted=false")
List<Customer> getAllCustomers();
}
Iinstead of:
cutomerRepository.findByIsDeletedFalse()
You missed one more Is at the name of the method.
Update your Domain:
public class Customer implements Serializable {
private final static long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
#Column(name = "serial_number")
private Long serialNumber;
// ...
#Column(name = "is_deleted")
private Boolean isDeleted;
}
JPA fields should be Objects instead of primitives. And entity class should implement Serializable as well.
If the exception will be the same you could try to update #Query:
#Query("from Customer c where c.isDeleted=0")
If pure SQL works for your DB you could use native query:
#Query(
value = "select * from Customer where is_deleted = false",
nativeQuery = true)
List<Customer> getAllCustomers();
It's not working because it doesn't follow the naming conventions for a boolean field. Usually in Java the primitive booleans are named without is prefix and the getter would be using this is prefix.
So in your case your entity class should look like that:
public class Customer {
// ...
#Column(name = "is_deleted")
private boolean deleted;
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
}
Also the naming of the spring repository method should be:
List<Customer> findAllByDeletedIsFalse();
In case you want to use a Boolean reference type you can name your field isDeleted, but then the class would look like that:
public class Customer {
// ...
#Column(name = "is_deleted")
private Boolean isDeleted;
public Boolean getIsDeleted() {
return isDeleted;
}
public void setIsDeleted(Boolean isDeleted) {
this.isDeleted = isDeleted;
}
}
and the repository method:
List<Customer> findAllByIsDeletedIsFalse();
Boolean Java maps a bit datatype column. You are probably using int as datatype in your database.
I have two entity that have a relation,The relationship works fine, but how can I set value from one object to another in controller.
#Entity
#Table(name = "material_manu_calculator")
public class MaterialManuCalcu {
#Id
#GeneratedValue
#Column(name = "no")
private int no;
#ManyToOne
#JoinColumn(name = "order_id")
private OrderProductManu orderProductManu;
//.....getters and setters and constructors}
Below is the second Entity
#Entity
#Table(name = "orders_products_manu")
public class OrderProductManu {
#Id
#GeneratedValue
#Column(name = "order_id")
private int orderManuId;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "orderProductManu")
private List<MaterialManuCalcu> materialCalcu = new ArrayList<>();
//.....getters and setters and constructors}
below is the Repository
#Repository
#Transactional
public interface OrderProductManuRepository extends JpaRepository <OrderProductManu, Integer> {
#Query(value ="SELECT *FROM orders_products_manu WHERE orders_products_manu.order_id =?", nativeQuery = true)
public OrderProductManu getOrderProductById(int id);
}
I want to set the value of MaterilaManuCalcu in controller as below
#Controller
public class ProductsController {
#Autowired
private OrderProductManuRepository orderRepo;
OrderProductManu orderProduct = orderRepo.getOrderProductById(1);
MaterialManuCalcu manCalc = new MaterialManuCalcu();
manCalc.setOrderProductManu(orderProduct.getOrderManuId());
// I get the error says:
// The method setOrderProductManu(OrderProductManu) in
// the type MaterialManuCalcu is not applicable for the arguments (int)
Update: Constructors
public MaterialManuCalcu(int no, int amountOrdered, int amountAvailable, int amountWillRemain,
MaterialManu materialmanu, OrderProductManu orderProductManu) {
this.no = no;
this.amountOrdered = amountOrdered;
this.amountAvailable = amountAvailable;
this.amountWillRemain = amountWillRemain;
this.materialmanu = materialmanu;
this.orderProductManu = orderProductManu;
}
Another one
public OrderProductManu(int orderManuId, String customerName, int amountOrderedManu, String dateOrdered, Users users,
ProductsManu productsManu) {
this.orderManuId = orderManuId;
this.customerName = customerName;
this.amountOrderedManu = amountOrderedManu;
this.dateOrdered = dateOrdered;
this.users = users;
this.productsManu = productsManu;
}
Update:Showing how both entities are created
For : OrderProductManu
OrderProductManu orderProduct = new OrderProductManu();
orderProduct.setDateOrdered("2021-04-14");
orderProduct.setAmountOrderedManu(platenum);
orderProduct.setCustomerName("Wapili Mteja");
orderProduct.setUsers(userMoja.get(0));
orderProduct.setProductsManu(typeofProduct);
orderProductManus.setOrderManuId(007);//this is the value that I want to set inside
//MateriaManCalcu entity for property setOrderProductManu
//You can check the relationship above
For: MaterialManuCalcu
MaterialManuCalcu manCalc = new MaterialManuCalcu();
manCalc.setAmountAvailable(availableSheets);
manCalc.setAmountOrdered(sheetsNum);
manCalc.setAmountWillRemain(sheetWillRemain);
manCalc.setMaterialmanu(materialSheet);
manCalc.setOrderProductManu(orderProduct);//doing this the whole object of
//orderProduct entity goes inside a one column in our MatrialManuCalcuof entity
Table:material_manu_calculator
How should I do this correctly. Thanks in advance.
You are trying to set id of orderProduct which is returned by calling orderProduct.getOrderManuId() of type int to variable of type OrderProductManu.
Just pass your orderProduct like this manCalc.setOrderProductManu(orderProduct)
I am using Spring-Boot with JPA and a MySQL backend. Now I got quite confused about the repositories Spring-Boot provides. I know these are quite powerful (and seem to be quite useful since they can shorten your code a lot). Still, I do not understand how to represent Joins within them, since the result-set should be a combination of specified attributes in the select of a few Entities.
Now let's assume we have three tables Book, Author, AuthorOfBook, where the last one is simply connecting Book and Author by a combined Primary key. I guess we had the following Java-Classes:
Entity Book:
#Entity
#Table(name="BOOK")
public class Book {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "TITLE")
private String title;
}
Entity Author
#Entity
#Table(name="AUTHOR")
public class Author {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "LASTNAME")
private String lastname;
#Column(name = "FIRSTNAME")
private String firstname;
//Let's assume some getters and setters and a constructor
}
Entity AuthorOfBook:
#Entity
#Table(name="BOOK")
public class Book {
#EmbeddedId
private AuthorOfBookId pk;
}
An Embedded ID
#Embeddable
public class AuthorOfBookId implements Serializable {
private int authorId;
private int bookId;
}
Repository
#Repository
public interface AuthorOfBookRepository extends JpaRepository<,AuthorOfBookId> {
}
Now how would I represent that query:
SELECT b.name, a.firstname, a.lastname from AuthorOfBook ab inner join Book b on b.id = ab.book_id inner join Author a on a.id = ab.author_id where a.lastname = :lastname;
in my repository? I know the signature would need to be like
#Query([the query string from above])
public (...) findAuthorAndBookByAuthorLastname(#Param("lastname") String lastname);
but I cannot make out what Type the return would be like. What is that method returning? (simply AuthorOfBook would not work I guess)
You don't want AuthorOfBook as a separate Entity. Book should have a field of type Author as a #ManyToOne relationship. That way, given any Book, you can find the author's details.
If you want to handle audits fields you can do something like this:
Audit class
#Embeddable
public class Audit {
#Column(name = "created_on")
private Timestamp createdOn;
#Column(name = "updated_on")
private Timestamp updatedOn;
#Column(name = "is_deleted")
private Boolean isDeleted;
//getters and setters
}
AuditListener to update automatically audits fields
public class AuditListener {
private Long loggedUser = 1001L;
/**
* Method to set the fields createdOn, and isDeleted when an entity is persisted
* #param auditable
*/
#PrePersist
public void setCreatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
if (audit == null) {
audit = new Audit();
auditable.setAudit(audit);
}
audit.setIsDeleted(Boolean.FALSE);
audit.setCreatedOn(Timestamp.from(Instant.now()));
}
/**
* Method to set the fields updatedOn and updatedBy when an entity is updated
* #param auditable
*/
#PreUpdate
public void setUpdatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
audit.setUpdatedOn(Timestamp.from(Instant.now()));
}
}
And add this to the entities
#EntityListeners(AuditListener.class)
public class Book implements Auditable {
#Embedded
private Audit audit;
I am currently developing an application with Spring (Boot) and JPA. I have the following two entities:
#Entity
#AccessType(AccessType.Type.PROPERTY)
#Table(name = "T_ORDER")
public class Order {
#Id
private String id;
#Version
private Integer version = 0;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "order", cascade = CascadeType.ALL)
private List<Item> items = new ArrayList<>();
private String text;
private String status;
#Deprecated
public Order() {}
public static Order newOrder() {
Order order = new Order();
order.id = UUID.randomUUID().toString();
return order;
}
[... getters and setters ...]
[... equals and hashCode ...]
}
and
#Entity
#Table(name = "T_ITEM")
#IdClass(Item.ItemId.class)
public class Item {
public static class ItemId implements Serializable {
public String order;
public String id;
[... equals and hashcode ...]
}
#Id
#JsonIgnore
#ManyToOne(cascade = CascadeType.PERSIST)
private Order order;
#Id
private String id;
#Version
private int version = 0;
#Transient
private Product product;
private Integer productId;
private BigDecimal quantity;
private String quantityUnit;
private BigDecimal price;
[... getters and setters ...]
[... equals and hashcode ...]
}
I am using a CRUDRepository
#Repository
public interface OrderRepository extends CrudRepository<Order, String> {
#Transactional
List<Order> removeByStatus(String status);
}
to insert data on application startup
#Component
public class OrderLoader implements ApplicationListener<ContextRefreshedEvent> {
private final Logger logger = LoggerFactory.getLogger(getClass());
private OrderRepository orderRepository;
#Autowired
public void setOrderRepository(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
#Override
#Transactional(readOnly = false)
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
try {
Order order = Order.newOrder();
for (int itemId = 1; itemId < 3; itemId++) {
Item item = order.addItem();
item.setProductId(1);
}
order.setText("this is an order");
order.setStatus("delivered");
orderRepository.save(order);
} catch (Exception e) {
logger.error("This shit...", e);
}
}
}
Using the H2 console, I can see that the tables are being generated and empty. However, I get a DataIntegrityViolationException when calling orderRepository.save(order).
This seems very strange to me as :
The tables are empty,
I am using UUIDs as IDs and
save should merge two entities with the same key.
The complete stacktrace: http://pastebin.com/gYk2ZvP4
Try to use orderRepository.saveAndFlush(order); instead of orderRepository.save(order);, with saveAndFlush changes will be flushed to DB immediately,while using just save changes won't apply to database until flush or commit are issued.
I am new to hibernate and having a tough time trying to wrap my head around setting up Joined inheritance with composite Primary Key. With my current setup, I get a:
JDBCException: could not insert: LandHolidayPackage
I am essentially looking for two things:
Are the inheritance annotations in place ?
Is the composite PK setup properly ?
DB Design:
Reference
Here are my classes and the annotations involved:
#Entity
#Table(name = "HOLIDAYPACKAGE")
public final class HolidayPackage {
private Integer idPackage;
private String name;
private Set<HolidayPackageVariant> holidayPackageVariants = new HashSet<HolidayPackageVariant>(0);
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "IDHOLIDAYPACKAGE", nullable = false)
public Integer getIdPackage() {
return idPackage;
}
#OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL}, mappedBy = "holidayPackage")
public Set<HolidayPackageVariant> getHolidayPackageVariants() {
return holidayPackageVariants;
}
// ommitted other part of the code
}
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#Table(name="HOLIDAYPACKAGEVARIANT")
public abstract class HolidayPackageVariant {
private Integer idHolidayPackageVariant;
private HolidayPackage holidayPackage;
private String typeHolidayPackage;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="IDHOLIDAYPACKAGEVARIANT", nullable=false)
public Integer getIdHolidayPackageVariant() {
return idHolidayPackageVariant;
}
#ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
#JoinColumn(name="IDHOLIDAYPACKAGE", nullable=false)
public HolidayPackage getHolidayPackage() {
return holidayPackage;
}
#Column(name="TYPEHOLIDAYPACKAGE", nullable=true)
public String getTypeHolidayPackage() {
return typeHolidayPackage;
}
// ommitted setters, equals hashCode
}
#Entity
#Table(name="LANDHOLIDAYPACKAGEVARIANT")
public final class LandHolidayPackageVariant extends HolidayPackageVariant{
private static final String LAND = "LAND";
protected LandHolidayPackageVariant() {}
public LandHolidayPackageVariant(HolidayPackage holidayPackage) {
super(holidayPackage, LAND);
}
}
#Entity
#Table(name="FLIGHTHOLIDAYPACKAGEVARIANT")
public final class FlightHolidayPackageVariant extends HolidayPackageVariant{
private static final String FLIGHT = "FLIGHT";
private Destination originCity;
protected FlightHolidayPackageVariant(){}
public FlightHolidayPackageVariant(HolidayPackage holidayPackage,
Destination originCity) {
super(holidayPackage, FLIGHT);
setOriginCity(originCity);
}
#ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
#JoinColumn(name="IDDESTINATION", nullable=false)
public Destination getOriginCity() {
return originCity;
}
// ommited other setters etc functions
}
You annotated the properties in stead of the fields. JPA by default tries to access the fields. If you want JPA to use the fields you have to annotate the class with #AccessType(AccessType.Field).