how to access to subproperties with jpa metamodel in where clause - jpa

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

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.

Load tables only with some specific conditions (#Where)

What I'm trying to do is to load only promotions with promotion.enabled=1 AND PromotionType.enabled=1.
I tried to add the #Where annotation in both tables but when I set promotionType, enabled to 0 I´m getting an error.
On the other hand, I also tried to add the #WhereJoinTable clause to promotionType but I'm not getting the expected result. Any help?
The first one:
#Entity
#Table(name = "HOTEL_PROMOTION")
#Where(clause = "enabled=1")
public class Promotion implements Serializable {
private static final long serialVersionUID = 257070400893576505L;
#Id
#Column(name = "PROMOTION_ID")
private Long id;
#Column(name = "CODE")
private String code;
#Column(name = "NAME")
private String name;
#Column(name = "PRIORITY")
private Long priority;
#ManyToOne
#JoinColumn(name = "PROMOTION_TYPE_ID")
#WhereJoinTable(clause = "enabled=1")
private PromotionType promotionType;
#Column(name = "ENABLED")
private Boolean enabled;
}
The second one:
#Entity
#Table(name = "HOTEL_PROMOTION_TYPE")
public class PromotionType implements Serializable {
private static final long serialVersionUID = -8359165117733458987L;
#Id
#Column(name = "PROMOTION_TYPE_ID")
private Long id;
#Column(name = "CODE")
private String code;
#Column(name = "NAME")
private String name;
#Column(name = "STYLE")
private String style;
#Column(name = "ENABLED")
private Boolean enabled;
}

org.springframework.dao.InvalidDataAccessResourceUsageException in spring data jpa

i have (one to many) and (many to one) bi-directional mappings while i am querying with #Query with spring- data-jpa using repository using foreign key iam getting InvalidDataAccessApiUsageException
#Entity(name="docket")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Docket implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
#Column(name="docket_Id")
private long Id;
#Column(name="docket_name")
private String docket_name;
#Column(name="area_in_kms")
private long area_in_kms;
#Column(name="number_of_connections")
private long number_of_connections;
#Column(name="number_of_sewer_connections")
private long number_of_sewer_connections;
#Column(name="number_of_manholes")
private long number_of_manholes;
#Column(name="deep_manholes")
private long deep_manholes;
#Column(name="contour_low")
private long contour_low;
#Column(name="contour_high")
private long contour_high;
#Column(name="length_of_sewermain_kms")
private long length_sewer_in_kms;
#JsonBackReference(value="section-details")
#ManyToOne(cascade= CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "section_Id")
private Section section;
#Entity(name="section")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Section implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="section_Id")
private long Id;
#Column(name="section_name")
private String section_name;
#Column(name="area_in_kms")
private long area_in_kms;
#Column(name="calculated_length")
private long calculated_length;
#Column(name="area_geometry")
private long area_geometry;
//#JsonManagedReference
#OneToMany(mappedBy = "section", cascade = CascadeType.ALL,fetch = FetchType.LAZY)
private Set<Docket> docket;
#Repository
#Transactional(readOnly = true)
public interface DocketRepository extends JpaRepository<Docket, Long> {
#Modifying(clearAutomatically = true)
#Query(nativeQuery=true,value= "select d from docket d where d.section_id = :section_id" )
List<Docket> findAlldocketsforsection(#Param("section_id") long id);
need help!! on this i need to query more custom queries in this api please suggest me from where i am getting error

JPA query with OneToOne lazy

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

Performance bottleneck with EclipsLink 2.0

Recently while I was using EclipsLink 2.0 I run into performance bottleneck problem with my implementation of persisting objects.
To be more specific I used to have the following implementation:
#Entity
#Table(name = "CUSTOMERS")
public class CustomerEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private volatile Long id;
#Column(nullable = false, unique = true)
private String name;
private static final long serialVersionUID = 6952530957072210017L;
private String custGroup;
private String address;
private String nameOfFirstPerson;
private String contactPerson;
private String phone;
private String fax;
private String email;
private String comments;
private String defaultCustomer;
private volatile boolean delayedPaymentAllowed;
private volatile long periodOfDelayedPaymentAllowed;
private volatile boolean restrictionsOnDelayedPayment;
private volatile double maxAmoutPemittedSom;
private volatile double maxAmoutPemittedYE;
private transient String salesPointName;
#Column(length=25483)
private HashMap<String, PriceItem> totalBalance;
#Column(length=25483)
private HashMap<String, PriceItem> totalBalanceUsd;
private transient boolean valueChanged = false;
#OneToMany(mappedBy = "supplier")
private Collection<PurchaseInvoiceEntity> purchaseInvoices;
#OneToMany(mappedBy = "receiver")
private Collection<SalesInvoiceEntity> salesInvoices;
#OneToMany(mappedBy = "payer")
private Collection<PayInSlipEntity> payInSlips;
#OneToMany(mappedBy = "recipient")
private Collection<PaymentOrderEntity> paymentOrders;
#OneToMany(mappedBy = "recipient")
private Collection<WriteOffEntity> writeOffs;
#ManyToOne()
private ResponsiblePersonForDebtEntity responsiblePersonForDebt;
#ManyToOne
private CustomerGroupEntity customerGroup;
public CustomerEntity() {
valueChanged = false;
}
...
}
and while each time I was adding an instance of new document into appropriate Collection while inserting a new instance of document into a table I detected that it takes too long to insert the document. I come across of this problem while I was using profiler module of netbeans ide 6.9. Actually I was using these collections in order to check for emptiness with related documents.
In order to tackle the problem I simply applied the following solution:
I simply removed document references :
#OneToMany(mappedBy = "supplier")
private Collection purchaseInvoices;
#OneToMany(mappedBy = "receiver")
private Collection salesInvoices;
#OneToMany(mappedBy = "payer")
private Collection payInSlips;
#OneToMany(mappedBy = "recipient")
private Collection paymentOrders;
#OneToMany(mappedBy = "recipient")
private Collection writeOffs;
from the CusotmerEntity:
#Entity
#Table(name = "CUSTOMERS")
public class CustomerEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private volatile Long id;
#Column(nullable = false, unique = true)
private String name;
private static final long serialVersionUID = 6952530957072210017L;
private String custGroup;
private String address;
private String nameOfFirstPerson;
private String contactPerson;
private String phone;
private String fax;
private String email;
private String comments;
private String defaultCustomer;
private volatile boolean delayedPaymentAllowed;
private volatile long periodOfDelayedPaymentAllowed;
private volatile boolean restrictionsOnDelayedPayment;
private volatile double maxAmoutPemittedSom;
private volatile double maxAmoutPemittedYE;
private transient String salesPointName;
#Column(length = 25483)
private HashMap<String, PriceItem> totalBalance;
#Column(length = 25483)
private HashMap<String, PriceItem> totalBalanceUsd;
private transient boolean valueChanged = false;
#ManyToOne()
private ResponsiblePersonForDebtEntity responsiblePersonForDebt;
#ManyToOne
private CustomerGroupEntity customerGroup;
public CustomerEntity() {
valueChanged = false;
}
.....}
while checking for references for the documents I used JPA query while editing or deleting CustomerEntity.
This simple change removed the most affecting performance problem.
Side Note:
Please while using performance profiler include a check for package methods too(eclipslink for ex.)
For performance and scalability issues in JPA please read or listen S"Strategies and Best Practices for Highly Scalable Java Persistence Applications" by Gordon Yorke.