JPA : query is not cached because it generates multiple SQL statements - jpa

I am getting so many warning message log.
Query is not cached because it generates multiple SQL statements. A query can be cached only when it corresponds to a single SQL statement
Runtime W CWWJP9991W: openjpa.Runtime: Warn: Query "SELECT ent FROM Event ent ORDER BY ent.name" is removed from cache excluded permanently.
Query "SELECT ent FROM Event ent ORDER BY ent.name" is not cached because it generates multiple SQL statements.
A query can be cached only when it corresponds to a single SQL statement. .
#Entity
#Table(name="EVENT")
public class Event {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="GEN_ID")
private Long genId;
#Column(name="NAME")
private String name;
#Column(name="LOCATION")
private String location;
#Column(name="EVENT_ID")
private String eventID;
#Temporal(TemporalType.TIMESTAMP)
#Column(name ="CREATION_DATE",nullable=false)
private Date creationDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name ="START_DATE")
private Date startDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name ="END_DATE")
private Date endDate;
#Column(name="STATUS")
private String status;
#Column(name="LANGUAGE")
private String language;
#Column(name="ACTIVE")
private Boolean active;
#Column(name="ACCESS_CONTROL")
private Boolean accessControl;
#Column(name="FILE_NAME")
private String fileName;
}

Related

Creating a query with a one-to-one relationship

I have two tables...a loan table and a customer table. A customer can make multiple loans but I would like to restrict the customer to one active loan at a time. They cannot create a second loan until the first loan is finished (loan.active=false)
I have set up my loan table like this :
#Entity
public class Loan implements Serializable {
private static final long serialVersionUID = 0x62B6DA99AA12AAA8L;
#Column #GeneratedValue(strategy = GenerationType.AUTO) #Id private Integer id;
#OneToOne(fetch = FetchType.LAZY)
private Customer customer;
#Column private String dateLoaned;
#Column private String dateToReturn;
#Column private String dateOfReturn;
#Column private Boolean active=false;
And the customer table like this :
#Entity
public class Customer implements Serializable {
private static final long serialVersionUID = 0x63A6DA99BC12A8A8L;
#Column #GeneratedValue(strategy = GenerationType.AUTO) #Id private Integer id;
#Column private String firstname;
#Column private String surname;
#Column private String address;
#Column private String town;
#Column private String postcode;
#Column (unique=true) private String personalnumber;
#Column (unique=true) private String emailaddress;
#OneToOne(fetch = FetchType.EAGER)
private Loan loan;
This allows me to create a new loan with the same customer. So far so good.
I would like to make a query that allows me to find if a customer already has an active loan.
My loan repository so far is :
#Query("select loan_id from Loan l where l.customer.id = :customerId and l.active = true")
Boolean customerHasActiveLoan(#Param("customerId") Integer customerId);
Is this the correct way to do this?
In spring-data-jpa you can both have #Query or write a method that generates a query. There is nothing wrong to have #Query but because your repository method is quite simple you can use also method name only
For the example the equivalent of:
//Will return the active loan, if exists, or null
#Query("select l from Loan l where l.customer.id = :customerId and l.active = true")
public Loan getActiveLoad(#Param("customerId") Integer customerId)
could be simplified as
public Local findOneByCustomerIdAndActiveIsTrue(Long id)
Sometimes method name approach can generate long method name, and for this reason, if you prefer, you can use #Query annotation

JPA is not creating TIME part of TIMESTAMP

I have an entity like below
#Entity
#Table(name="PRODUCTS")
public class Feed implements Serializable{
private static final long serialVersionUID = -1732936132016478456L;
#Id
#GeneratedValue( strategy = GenerationType.AUTO)
#Column(name = "ID")
private int id;
#Column(name = "IMAGE_PATH")
private String imagePath;
#Column(name = "DESCRIPTION")
private String description;
#ManyToOne
#JoinColumn(name="UPLOADER", nullable = false)
private User uploader;
#Column(name = "TAGS")
private String tags;
#Column(name = "DATE", columnDefinition="")
private Date date;
#Column(name = "LINK")
private String link;
}
I'm using below code to create entity
#Transactional
#Override
public Feed createFeed(Feed feed) {
this.entityManager.persist(feed);
this.entityManager.flush();
}
Everything is working perfectly but DATE column which is of type timestamp and set to CURRENT_TIMESTAMP as default is only populating Date part not time part.
I tried firing manual query and that populated timestamp properly.
Am I missing anything there?
If the Date is of type java.sql.Date JPA will only store the Date part in the database field.
If it's java.util.Date you must add #Temporal(TemporalType.TIMESTAMP) to also store the time part.
The TemporalType defines the precision of the date.
https://docs.oracle.com/javaee/6/api/javax/persistence/TemporalType.html
I got the solution.
I still don't know the reason and that is why i am not marking this as answer.
I annotated my date variable with #Temporal(TemporalType.DATE) and just that did the trick.
One thing to note: I had used java.util.Date

Spring data jpa JOIN does't work in #Query

I am using spring-data-jpa. I wrote a native query but it doesn't work. Here is my entity classes:
#Entity
#Table(name="view_version")
public class ViewVersionDom {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name="view_id")
private ViewDom view;
private Integer version;
#ManyToOne
#JoinColumn(name="datasource_param_id")
private DatasourceParamDom datasourceParam;
private String description;
#Column(name="created_date")
private Date createdDate;
#Entity
#Table(name="view_permission")
public class ViewPermissionDom extends BaseDom {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name="view_id")
private ViewDom view;
#ManyToOne
#JoinColumn(name="user_id")
private UserDom user;
#ManyToOne
#JoinColumn(name="group_id")
private GroupDom group;
private Boolean read;
private Boolean write;
private Boolean execute;
Here is the query:
#Query(value = " SELECT v FROM ViewVersionDom v LEFT JOIN ViewPermissionDom vp ON v.view.id = vp.id "
+ " where (v.view.user.id = ?1 OR (vp.read=true and (vp.user.id=?1 or vp.user.id is NULL and vp.group.id is NULL or vp.group.id in (?2)))) "
+ " ORDER BY v.view.name", nativeQuery=true)
public List<ViewVersionDom> findUserViews(Long userId, List<Long> groupIds);
At first when I didn't write nativeQuery=true the application didn't build and I got an exception 'path expected for join jpa'. When I set the settings nativeQuery=true the application is started, but when I call the function I got the following error:
org.hibernate.engine.jdbc.spi.SqlExceptionHelper - [ERROR: relation "viewversiondom" does not exist Position: 16]
org.hibernate.exception.SQLGrammarException: could not extract ResultSet]
Does there any other settings or annotation that will resolve the problem?
I have searched in google, but in all cases 2 tables connected with each other directly.
Your query is not a SQL query (assuming, you don't have a column v in one for your tables).
Also the Table viewversiondom doesn't exist or is not accessible to the database user used for the connection.
Also when mapping native queries to domain objects you should have a look at https://jira.spring.io/browse/DATAJPA-980

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

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.