JPA query with OneToOne lazy - jpa

I have this structure of object
#Entity
public class Member {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long memberId;
private String name;
private boolean man;
private String address;
#OneToOne(fetch = FetchType.LAZY)
private City city;
private String postalCode;
private String phone1;
private String phone2;
private LocalDate birthdate;
private String email;
private String emergencyContactName;
private String emergencyPhone;
private String paymentGatewayKey;
#OneToMany(fetch = FetchType.LAZY)
private List<Contract> contracs;
#OneToOne(fetch = FetchType.LAZY)
private Commerce commerce;
}
#Entity
public class Contract {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long contractId;
private BigDecimal price;
private int frequency;
private int term;
private LocalDate startDate;
private LocalDate endDate;
private int numberOfPayment;
#Enumerated(EnumType.STRING)
private StatusEnum status;
#OneToMany(fetch = FetchType.LAZY,mappedBy = "contract")
private List<Payment> payments;
#ManyToOne
private Member member;
}
#Entity
public class Payment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long paymentId;
private BigDecimal price;
private LocalDate date;
#Enumerated(EnumType.STRING)
private StatusEnum status;
#Enumerated(EnumType.STRING)
private PaymentModeEnum paymentMode;
#ManyToOne
private Contract contract;
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
private List<Operation> operations;
}
is it possible from a member query to get only the needed contract, payment, city and commerce info?
If member have many contract... i want to get only contract #2...
I started this query but city and commerce are lazy and i don't know what to do with theses fields.
select m from Member m inner join fetch m.contracs c inner join fetch c.payments p where c.contractId = :contractId

Related

JPA Composite Key: Avoid Unnecessary of Table Creation

I am learning JPA.
I need to create 3 tables, product (pk => id), cart (pk => id), cart_details (pk also fk => product_id, cart_id).
The relation is : One cart can contain multiple cart_details, one cart_details can contain multiple product and one product can be put on multiple cart_details. I need only 3 tables, but JPA creates 4 tables for me: product, cart, cart_details, cart_details_product
#Entity
#Table(name = "product")
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#NotBlank
#Size(max = 50)
private String name;
#Size(max = 300)
private String description;
#NotNull
private Double price;
private int qty;
#Column(name = "created_date")
private Date createdDate;
#Column(name = "updated_date")
private Date updatedDate;
}
#Entity
#Table(name = "cart")
public class Cart implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "total_price")
private double totalPrice;
#Column(name = "created_date")
private Date createdDate;
#Column(name = "updated_date")
private Date updatedDate;
}
#Entity
#Table(name = "cart_details")
public class CartDetails implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private CartDetailsId id;
#MapsId("cartId")
#ManyToOne
#JoinColumn(name = "cart_id", referencedColumnName = "id", insertable = false, updatable = false)
private Cart cart;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "product_id", referencedColumnName = "id")
private Set<Product> product;
private int quantity;
private double price;
}
#Embeddable
public class CartDetailsId implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "cart_id")
private Long cartId;
#Column(name = "product_id")
private Long productId;
}
How to avoid creation of this table (cart_details_product)? I think i don't need this table.

Why is there a loop in #OneToMany mapping?

I am trying to create a #OneToMany database using JPA. There is a object Flight and a object Passenger.
the code:
#Entity
#Table(name = "passengers")
public class Passenger {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
private String email;
private String phoneNumber;
private String birthDate;
#ManyToOne(optional = false)
#JoinColumn(name = "flight_id")
private Flight flight;
public Passenger() {
}
public Passenger(String name, String surname, String email, String phoneNumber, String birthDate, Flight flight) {
super();
this.name = name;
this.surname = surname;
this.email = email;
this.phoneNumber = phoneNumber;
this.birthDate = birthDate;
this.flight = flight;
}
#Entity
#Table(name = "flights")
public class Flight {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "flight_id")
private long id;
private String departure;
private String destination;
private String date;
private int capacity;
private float price;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "flight", cascade = CascadeType.ALL)
private Set<Passenger> passengers;
public Flight() {
}
public Flight(String departure, String destination, String date, int capacity, float price) {
super();
this.departure = departure;
this.destination = destination;
this.date = date;
this.capacity = capacity;
this.price = price;
}
this is how I add a new Passenger:
#PostMapping("/flights")
public ResponseEntity<Object> updateFlight(#RequestBody Flight flight) {
long id = flight.getId();
Optional<Flight> flightOptional = flightRepository.findById(id);
if (!flightOptional.isPresent())
return ResponseEntity.notFound().build();
int currentCapacity = flight.getCapacity();
flight.setCapacity(currentCapacity - 1);
for(Passenger passenger : flight.getPassengers()) {
System.out.println(passenger.getName());
}
this.flightRepository.save(flight);
return ResponseEntity.noContent().build();
}
Unfortunately, when I map the flights and passengers, I appear to have a never ending loop. Passengers have the details of the flight and passengers and again flight and then passengers, and so on.
Is there any way I can resolve it? Am I missing anything?
To avoid the cyclic problem Use #JsonManagedReference, #JsonBackReference as below.
Add #JsonManagedReference on Parent class
#JsonManagedReference
#OneToMany(fetch = FetchType.EAGER, mappedBy = "flight", c
ascadee = CascadeType.ALL)
private Set<Passenger> passengers;
Add #JsonBackReference on child class as below
#JsonBackReference
#ManyToOne(optional = false)
#JoinColumn(name = "flight_id")
private Flight flight;

Spring Boot : Building object Rest API

I created 4 classes for 3 tables. Those tables are built to store orders with products.
My first entity is orders :
#Entity
#Table(name="orders")
public class OrderEntity implements Serializable {
...
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
private UserEntity seller;
private String paymentMode;
private double totalAmount;
#OneToMany(mappedBy = "pk.order")
private List<OrderProductEntity> orderProducts;
#DateTimeFormat
private Date createdAt;
...
}
My second entity is products:
#Entity
#Table(name="products")
#Getter #Setter
public class ProductEntity implements Serializable {
...
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String productKeyId;
#ManyToOne
#JoinColumn(name = "category_id")
private CategoryEntity category;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private double price;
#Column(nullable = false)
private int availableQty;
#JsonManagedReference
#OneToMany(mappedBy = "pk.product", fetch = FetchType.EAGER)
#Valid
private List<OrderProductEntity> orderProducts;
...
}
I also define the pivot table in the OrderProductEntity:
#Entity
#Table(name="order_product")
#Getter #Setter
public class OrderProductEntity {
#EmbeddedId
#JsonIgnore
private OrderProductPK pk;
#Column(nullable = false)
private Integer quantity;
// default constructor
public OrderProductEntity(){}
public OrderProductEntity(OrderEntity order, ProductEntity product, Integer quantity) {
pk = new OrderProductPK();
pk.setOrder(order);
pk.setProduct(product);
this.quantity = quantity;
}
}
And I defined the PK of this table :
#Embeddable
#Getter #Setter
public class OrderProductPK implements Serializable {
#JsonBackReference
#ManyToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "order_id")
private OrderEntity order;
#ManyToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "product_id")
private ProductEntity product;
}
Now my issue is to return the data to the front office by a web service Rest.
I created a model that represent what i want to obtain as result.
public class OrderRest {
private String orderKeyId;
private String paymentMode;
private double totalAmount;
private List<ProductRest> orderProducts;
private UserRest seller;
private Date createdAt;
}
And :
public class ProductRest {
private String productKeyId;
private String name;
private double price;
private int qty;
private String imgPath;
private CategoryRest category;
}
In my controller i want to return an OrderRest object :
public List<OrderRest> getOrders() {
List<OrderRest> returnValue = new ArrayList<>();
List<OrderDto> orderDtos = orderService.getOrders();
// loop the result
for (OrderDto orderDto : orderDtos) {
OrderRest orderRest = new OrderRest();
ModelMapper modelMapper = new ModelMapper();
orderRest = modelMapper.map(orderDto, OrderRest.class);
returnValue.add(orderRest);
}
return returnValue;
}
THis method map the List of OrderRest and call the service layer :
public List<OrderDto> getOrders() {
List<OrderDto> returnValue = new ArrayList<>();
Iterable<OrderEntity> orderEntities = orderRepository.findAll();
ModelMapper modelMapper = new ModelMapper();
for(OrderEntity orderEntity: orderEntities) {
OrderDto orderDto = new OrderDto();
UserDto userDto = orderDto.getSeller();
List<OrderProductDto> orderProductDtos = orderDto.getOrderProducts();
orderDto = modelMapper.map(orderEntity, OrderDto.class);
returnValue.add(orderDto);
}
return returnValue;
}
With OrderDto :
public class OrderDto implements Serializable {
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private static final long serialVersionUID = 1L;
private Long id;
private String orderKeyId;
private String paymentMode;
private double totalAmount;
private List<OrderProductDto> orderProducts;
private UserDto seller;
private Date createdAt;
}
And OrderProductDto :
public class OrderProductDto implements Serializable {
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private static final long serialVersionUID = 1L;
private String productKeyId;
private String name;
private Integer price;
private Integer qty;
private String imgPath;
private CategoryDto category;
}
My issue is concerning what i return from the REST API :
my product list returns nothing :
"orderProducts": [
{
"productKeyId": null,
"name": null,
"price": 0.0,
"qty": 0,
"imgPath": null,
"category": null
},...
]

Error #OneToOne or #ManyToOne references an unknown entity

I receive an error like below and I do not know why?
Caused by: org.hibernate.AnnotationException: #OneToOne or #ManyToOne
on ##################.model.Orders.customerid references an unknown
entity: java.lang.Long
Class Orders
#Entity
public class Orders {
#Id
#GeneratedValue
private Long orderid;
#JoinColumn(name = "customerid", referencedColumnName = "CustomerID")
#ManyToOne
private Long customerid;
#JoinColumn(name = "employeeid", referencedColumnName = "EmployeeID")
#ManyToOne
private Long employeeid;
private java.sql.Timestamp orderdate;
private java.sql.Timestamp requireddate;
private java.sql.Timestamp shippeddate;
#JoinColumn(name = "shipperid", referencedColumnName = "ShipperID")
#ManyToOne
private Long shipvia;
private Double freight;
private String shipname;
private String shipaddress;
private String shipcity;
private String shipregion;
private String shippostalcode;
private String shipcountry;
#OneToMany(mappedBy="orderid")
private List<OrderDetails> orderDetails;
Class Customers
#Entity
public class Customers {
#Id
#GeneratedValue
private Long customerid;
private String companyname;
private String contactname;
private String contacttitle;
private String address;
private String city;
private String region;
private String postalcode;
private String country;
private String phone;
private String fax;
#OneToMany(mappedBy="customerid")
private List<Orders> orders;
Relation between this two entities are described here
Please explain me what am I doing wrong?
I found the reason after asking the question I apologize for the inconvenience. As You can see I forgot to change type for customerid it should by as follows
Class Orders
#Entity
public class Orders {
#Id
#GeneratedValue
private Long orderid;
#JoinColumn(name = "customerid", referencedColumnName = "CustomerID")
#ManyToOne
private Customers customerid;
#JoinColumn(name = "employeeid", referencedColumnName = "EmployeeID")
#ManyToOne
private Employees employeeid;
private java.sql.Timestamp orderdate;
private java.sql.Timestamp requireddate;
private java.sql.Timestamp shippeddate;
#JoinColumn(name = "shipperid", referencedColumnName = "ShipperID")
#ManyToOne
private Shippers shipvia;
private Double freight;
private String shipname;
private String shipaddress;
private String shipcity;
private String shipregion;
private String shippostalcode;
private String shipcountry;
#OneToMany(mappedBy="orderid")
private List<OrderDetails> orderDetails;
I had this error recently but with an unknown entity.
Initial SessionFactory creation failed.org.hibernate.AnnotationException: #OneToOne or #ManyToOne on XXXX.Terminal.location references an unknown entity: XXXX.dc.Location
Feb 06, 2020 11:51:38 AM org.apache.catalina.core.StandardContext listenerStart
In my case I had to add a mapping of this entity to the "hibernate.cfg.xml"
<mapping class="XXXX.dc.Location"/>

how to access to subproperties with jpa metamodel in where clause

I have a two entities with relation between they are.
public class Client implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Integer id;
#NotNull
#Size(min = 3, max = 25)
private String firstName;
#NotNull
#Size(min = 3, max = 25)
private String lastName;
private String login;
private String password;
#OneToMany(mappedBy = "client")
private List<Project> projects;
}
and
public class Project implements Serializable {
private static final long serialVersionUID = 4762714047114442539L;
#Id
#GeneratedValue
private Integer id;
private String name;
#Temporal(TemporalType.TIMESTAMP)
private Date startDate;
#ManyToOne
#JoinColumn
private Client client;
}
I want to made a query using jpametamodel and Criteria API. Like this:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Project> q = cb.createQuery(Project.class);
Root<Project> projects = q.from(Project.class);
q.where(cb.equal(projects.get(Project_.client), clientId));
Problem for me that i don't know how to get access to "id" property of Client in this string:
q.where(cb.equal(projects.get(Project_.client), clientId));
i want to get something like
q.where(cb.equal(projects.get("client.id"), clientId));
but with jpametamodel. It is possible? :)
Tried something like this?
projects.get(Project_.client).get(Client_.id);