How to select Entity A and your subclass Entity B with relationship OneToMany, using CriteriaBuilder construct? - jpa

Using CriteriaBuilder how to select Entity A and names from Entity B, with CriteriaBuilder construct?
Entity A
public class EntityA {
private Long id;
#OneToMany(mappedBy = "entityA", fetch = FetchType.LAZY)
private List<EntityB> entitiesB;
//get and set
}
Entity B
public class EntityB {
private Long id;
private String name;
#ManyToOne
private EntityA entityA;
//get and set
}

Related

Many To Many Relationship JPA with Entity

I have an issue trying to generate multiple relationship in JPA with three Entities.
Order
Product
Modifier
I have an Entity to handle the relationship many to many.
OrderProducts (order_id and product_id)
Contains the relationship of one order can have multiple products
OrderDetails (order_products_id and modifier_id)
Contains the id of the previous relationship Order-Products and the Id of the modifier which is a set of multiple values that can affect the price of the product.
Not quite sure how to handle this kind of relationship in JPA as I'm new to it.
You need a join entity with a composite key. You will need to research it further.
Your entities:
#Entity
#Table(name = "ordertable")
#Data
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "order")
#EqualsAndHashCode.Exclude
private Set<OrderProductModifier> products;
}
#Entity
#Table(name = "product")
#Data
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#EqualsAndHashCode.Exclude
private BigDecimal unitPrice;
}
#Entity
#Table(name = "modifier")
#Data
public class Modifier {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#EqualsAndHashCode.Exclude
private BigDecimal modifier;
}
And the entity that ties it all together will need to have the foreign keys for each of the above entities, as you have noted.
#Entity
#Table(name = "orderproductmodifier")
#Data
public class OrderProductModifier {
#EmbeddedId
private OrderProductModifierId id;
#MapsId("orderId")
#ManyToOne
#EqualsAndHashCode.Exclude
#ToString.Exclude
private Order order;
#MapsId("productId")
#ManyToOne
#EqualsAndHashCode.Exclude
private Product product;
#MapsId("modifierId")
#ManyToOne
#EqualsAndHashCode.Exclude
private Modifier modifier;
}
#SuppressWarnings("serial")
#Embeddable
#Data
public class OrderProductModifierId implements Serializable {
private Long orderId;
private Long productId;
private Long modifierId;
}
This is pretty simple to use:
private void run() {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("UsersDB");
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
Product product = new Product();
product.setUnitPrice(BigDecimal.TEN);
em.persist(product);
Modifier modifier = new Modifier();
modifier.setModifier(new BigDecimal(".90"));
em.persist(modifier);
Order order = new Order();
em.persist(order);
OrderProductModifier opm = new OrderProductModifier();
opm.setId(new OrderProductModifierId());
opm.setOrder(order);
opm.setProduct(product);
opm.setModifier(modifier);
em.persist(opm);
em.getTransaction().commit();
em.clear();
Order o = em.createQuery("select o from Order o join fetch o.products where o.id = 1", Order.class).getSingleResult();
System.out.println("Order for " + o.getProducts());
System.out.println("Order cost " + o.getProducts().stream().map(p->p.getProduct().getUnitPrice().multiply(p.getModifier().getModifier()).doubleValue()).collect(Collectors.summingDouble(Double::doubleValue)));
}
The above query could be better, but that will give you something to work on.

JPA entity mapping for embedded key

I have defined several JPA entities in a Spring Boot application.
#Entity
public class EntityA {
#Id
#Column(name = "id")
private String id
// ...
//....other fields
}
#Entity
public class EntityB {
#EmbeddedId
private MyEmbeddedId id;
// ....other fields
}
public class MyEmbeddedId {
#Column(name = "id_a")
private String idA;
#Column(name = "color")
private String color;
}
EntityA is self-sufifcient, EntityB has a composite key, one of whose constituent is primary key of EntityA(represented by column id_a). So I use embedded key feature here. There is a one-to-many relationship between EntityA and EntityB. An instance of EntityA can be mapped to multiple instances of EntityB.
Now, my objective is to fetch EntityA with all its associated EntityB.
How to go about mapping for this?
Try below Entity mappings,
#Entity
public class EntityA {
#Id
#Column(name = "id")
private String id
#OneToMany(mappedBy = "myEmbeddedId.idA",
cascade = CascadeType.ALL)
private Set<EntityB> entityB;
// ...
//....other fields
}
#Entity
public class EntityB {
#EmbeddedId
private MyEmbeddedId myEmbeddedId;
// ....other fields
}
public class MyEmbeddedId {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="id_a")
private EntityA idA;
#Column(name = "color")
private String color;
}
When you load EntityA, it will load all associated EntityB.

Spring Data JPA Projection nested list projection interface

I have a question about usage of nested list projection interface. I have two entity (Parent and child) (they have Unidirectional association)
Parent =>
#Table(name = "parent")
#Entity
public class ParentEntity {
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
// other fields........
}
Child =>
#Table(name = "child")
#Entity
public class ChildEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#NonNull
private String name;
#NonNull
#ManyToOne(fetch = FetchType.LAZY)
private ParentEntity parent;
// other fields........
}
I have two projection interface for select specific columns.
ParentProjection =>
public interface ParentProjection {
String getName();
Set<ChildProjection> getChild();
}
ChildProjection =>
public interface ChildProjection {
String getId();
String getName();
}
I want to take list of ParentProjection which includes with list of ChildProjection.
Repository query like that =>
#Query("select p.name as name, c as child from ParentEntity p left join ChildEntity as c on p.id = c.parent.id")
List<ParentProjection> getParentProjectionList();
This query works, but it selects all columns of ChildEntity, and map only id, name propeties to ChildProjection. (generated query selects all columns, but i want to select only id and name columns)
How can i select only id and name columns (select specific columns for nested list projection interface) and map to ChildProjection fields (using with #Query) ?
Note: I don't need to use class type projection.
You need to add the OneToMany relation to ParentEntity and annotate with Lazy.
Hope it helps (i have tried this).

Spring Data JPA order by value from OneToMany relation

I am trying to sort a result by nested collection element value. I have a very simple model:
#Entity
public class User {
#Id
#NotNull
#Column(name = "userid")
private Long id;
#OneToMany(mappedBy = "user")
private Collection<Setting> settings = new HashSet<>();
// getters and setters
}
#Entity
public class Setting {
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "userid")
private User user;
private String key;
private String value;
// getters and setters
}
public interface UserRepository extends JpaRepository<User, Long>, QuerydslPredicateExecutor<User> {
}
I want to have a result returned sorted by the value of one setting.
Is it possible to order by user.settings.value where settings.name = 'SampleName' using Spring Data JPA with QueryDSL?
I've used JpaSpecificationExecutor. let's see findAll for example.
Page<T> findAll(#Nullable Specification<T> spec, Pageable pageable);
Before call this method you can create your specification dynamically (where condition) and Pageable object with dynamic Sort information.
For example
...
Specification<T> whereSpecifications = Specification.where(yourWhereSpeficiation);
Sort sortByProperty = Sort.by(Sort.Order.asc("property"));
PageRequest orderedPageRequest = PageRequest.of(1, 100, sortByProperty);
userRepository.findAll(whereSpecifications, PageRequest.of(page, limit, orderedPageRequest));

JPA: When parent entity got removed, child entity still remain

Customer Entity (Parent Entity)
#Entity
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany(mappedBy="customer", cascade=CascadeType.ALL)
private List<Facility> facilities;
//Setter and Getter for name and facilities
public void addFacility(Facility facility){
if(this.facilities == null){
this.facilities = new ArrayList<Facility>();
}
this.facilities.add(facility);
facility.setCustomer(this);
}
}
Facility Entity (Child Entity)
#Entity
public class Facility {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name="CUSTOMER_FK")
private Customer customer;
private String name;
//Setter and Getter, equals and hashcode
...
}
in Customer entity, I use CascadeType.ALL, however when I remove a customer, the associated facilities are still there. I delete customer by
Query query = em.createNamedQuery("Customer.delete");
query.setParameter("id", customerId);
query.executeUpdate();
where
#NamedQuery(name="Customer.delete", query="delete from Customer c where c.id = :id")
Bulk delete operations are not cascaded, per JPA specification:
4.10 Bulk Update and Delete Operations
...
A delete operation only applies to
entities of the specified class and
its subclasses. It does not cascade to
related entities.
...
If you want to benefit from cascading, load the entity and then call EntityManager#remove(Object) on it.
Try with:
#Inject
EntityManager em;
Customer customer =...;
em.remove(customer);
This always cascades operations.