Spring data jpa JOIN does't work in #Query - spring-data-jpa

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

Related

#NamedQuery trying to fetch entity and related entity (#OneToOne relation) by related entity property

There are two entities:
#Entity(name = "Account")
#Table(name = "accounts")
#NamedQuery(name = "findAccountByExtId",
query = "SELECT a " +
"FROM Account a " +
"WHERE a.accountDetails.extId = :extId " +
"AND a.deletedAt IS NULL")
public class Account extends DeletableAudit {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private UUID id;
#OneToOne(mappedBy = "parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private AccountDetails accountDetails;
and
#Entity(name = "AccountDetails")
#Table(name = "account_details")
public class AccountDetails extends DeletableAudit {
private static final long serialVersionUID = -1L;
#Id
#GeneratedValue
private Integer accDetId;
#OneToOne
#JoinColumn(name = "fk_account")
private Account parent;
#Column
private String extId;
Goal is to return Account and AccountDetials via the external ID. The program won't run due to error:
Failed to create query for method public abstract p.j.o.d.d.Account p.j.o.d.r.AccountRepository.findAccountByExtId(java.lang.String)! No property extId found for type Account!
Already tried different variations of #OneToOne mapping and query, however nothing seems to work.
Second question is whether it is possible to have AccountDetails reference the same ID as Account. I'd like to get rid of accDetId and just store these entities with the same UUID of their parent.

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 Error joining table and view

I need to join a table and a view in a JPA query. The query won't compile because the view columns can't be identified.
Any suggestions are greatly appreciated.
Updated with parent entity and consistent naming
The query is:
select count(m.id)
from MultiSpeedMotor m,
MultiSpeedQuery q1
where m.id = q1.motorId
and q1.power = 10
The errors are:
The state field path 'q1.motorId' cannot be resolved to a valid type.
The state field path 'q1.power' cannot be resolved to a valid type.
I am working with a legacy database that has a denormalized table similar to this
Long motorId
Long id
Double hi_power
Double lo_power
I have used a view with a union query to normalize this table into
Long motorId
Long id
Long hi
Double power
To model the view of union query in JPA, I have used an #IdClass
public class MultiSpeedQueryId implements Serializable {
private static final long serialVersionUID = -7996931190943239257L;
private Long motorId;
private Long id;
private Long hi;
...
}
#Entity
#Table(name = "multi_speed_query")
#IdClass(MultiSpeedQueryId.class)
public class MultiSpeedQuery implements IMultiSpeedQuery {
#Id
#Column(name = "motor_id")
private Long motorId;
#Id
private Long id;
#Id
private Long hi;
private Double power;
...
}
The parent Entity is mapped as:
#Entity
#Table(name = "multi_speed_motor")
public class MultiSpeedMotor implements Serializable, IMultiSpeedMotor {
private static final long serialVersionUID = 3019928176257499187L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
}
The query is correct as written.
You CAN join Entities with no pre-defined relationship by using the syntax.
where a.id = b.joinField
The issue was much simpler. I missed part of the JPA error log that was telling the real problem.
The abstract schema type 'MultiSpeedQuery' is unknown.
Once I added the Entity to the persistence.xml, the query, as originally written, worked perfectly.

JPA Exception- Can not find constructor for <Class> with argument types "[class java.lang.String, class java.lang.String]" to fill data

I use jBoss Fuse 6.1.0 with blueprint DSL with openJPA. I use Container Managed transaction (JTA) and transaction managed by Aspects that handles Commit and Rollback as of now
I have following Classes that are JPA entities.
#Entity
#Table(name="CLIENT")
#NamedQuery(name="Client.findAll", query="SELECT c FROM Client c")
public class Client implements Serializable {
private static final long serialVersionUID = 1L;
//Had to add this for avoiding exception. And it works as expected
//Dummy constructor for JPA - Workaround
public Client(String s1, String s2){}
#Column(name="requestid", unique=true,nullable=false)
private String requestId;
#Id
#Column(name="clientid", unique=true, nullable=false, length=128)
private String clientId;
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name="REQUESTID", nullable=false)
private RoccoRequest roccoRequest;
//bi-directional One-To-Many association to ClientGroup
#OneToMany(mappedBy="client",fetch=FetchType.LAZY)
private List<ClientGroup> clientGroups;
....
,...
...
}
#Entity
#Embeddable
#Table(name="CLIENTGROUP")
#NamedQuery(name="ClientGroup.findAll", query="SELECT c FROM ClientGroup c")
public class ClientGroup implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private ClientGroupPK id;
#Column(length=32)
private String type;
#Column(name="clientid", length=128)
private String clientId;
//bi-directional many-to-one association to Client
#ManyToOne(fetch=FetchType.EAGER)
#MapsId("clientid")
#JoinColumn(name="CLIENTID", nullable=true, insertable=false, updatable=false)
private Client client;
..
.
.
.
}
#Entity
#Table(name="ROCCOREQUEST")
#NamedQuery(name="RoccoRequest.CHECK_EXISISTING_CLIENT_DETAILS",
query="SELECT r FROM RoccoRequest r JOIN r.client c WHERE c.crmId = :crmId")
public class RoccoRequest implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="requestid", unique=true, nullable=false, length=128)
private String requestId;
#OneToOne(mappedBy="roccoRequest", fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private Client client;
..
..
..
CriteriaQuery<Client> criteriaQuery = criteriaBuilder.createQuery(Client.class);
Root<Client> clientRoot = criteriaQuery.from(Client.class);
//Join the Client table with the RoccoRequest table
final Join<Client, RoccoRequest> clientRoccoJoin = clientRoot.join(Client_.roccoRequest,JoinType.INNER);
final Path<String> _requestStatus = clientRoccoJoin.get(RoccoRequest_.statusCode);
final Path<String> _requestId = clientRoccoJoin.get(RoccoRequest_.requestId);
final Predicate _crmIdPredicate = criteriaBuilder.equal(clientRoot.get(Client_.crmId), CRMId);
criteriaQuery.multiselect(_requestId,_requestStatus);
criteriaQuery.where(_crmIdPredicate);
//Get list of details of existing requests for the client with the request type as ACO
clientDetails = entityManager.createQuery(criteriaQuery).getResultList();
if(null != clientDetails) for(Client clientDetail : clientDetails){
StatusBO statusDetails = new StatusBO();
statusDetails.setCode((clientDetail.getRoccoRequest().getStatusCode()));
PreInitiationBO preinitiateDetails = new PreInitiationBO();
preinitiateDetails.getCaseHeader().setRequestId(requestId);
preinitiateDetails.setStatus(statusDetails);
exisitngRequestInfo.add(preinitiateDetails);
}
I have did some Criteria fetching of the entities. But I'm getting an exception as follows:
Can not find constructor for "class com.xxx.xxx.model.Client" with
argument types "[class java.lang.String, class java.lang.String]" to
fill data.
Why does JPA expect an argument Constructor? It has anything to do with the association? I tried removing the OneToMany relationship but I still get the error.
Please note that I have added a 2 argument constructor that makes no sense to me. But it works if it's given. log root level has Debug enabled. It has very less information on exception.
Please help.
As JBNizet pointed out,
I was making a dumb mistake by adding multiselect with two Strings but was having a CrtieriaQuery of type Client.class.
This can either be solved by removing the multiselect(Not in my case) or by Making the CriteriaQuery and other types with Tuples.class instead of Client.class and loop through the Tuples and get as tuple.get(0) etc.
Problem resolved. Thanks #Neil and #JBNizet

#OneToMany relationship property not filled

I have implemented Joined, Multiple Table Inheritance.
There is a 'parent' table pois and two sub tables: xPois and yPois and in turn I have an abstract PoiDao class as well as a XPoiDao and a YPoiDao class extending PoiDao.
A poi may have multiple reservations but a reservation belongs to exactly one poi.
Named queries defined in the child table DAOs work well for attributes defined in the respective (direct) table hierarchy. The parent table has a foreign key relationship to another table named reservations (table reservations holds the foreign key of table pois). The problem is that the records from this reservations table get not fetched.
Running this SQL statement in MySql Workbench gets the desired resultset:
SELECT * FROM xPois pp
LEFT JOIN pois p ON pp.poiId = p.poiId
LEFT JOIN reservations r ON p.poiId = r.poiId
WHERE pp.xPoiId = '2011';
In Eclipse I can see {IndirectList: not instantiated} when I inspect the xDao instance in debug mode.
How can I get the records from this table being stored in the PoiDao using JPA?
public abstract class PoiDao implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="poiId")
private Integer poiId;
#OneToOne(optional=false, cascade=CascadeType.ALL)
#JoinColumn(name="addressId",insertable=true,
updatable=true, unique=true, nullable=false)
private AddressDao address;
#Embedded
private GeoLocationDao geoLocation;
#Convert("poiTypeConverter")
private ServiceTypeEnum poiType;
#Column(name="operator")
private String operator;
#Column(name="reservable")
private boolean reservable;
#OneToMany(orphanRemoval=true, cascade=CascadeType.ALL, fetch=FetchType.LAZY)
#JoinColumn(name="poiId", insertable=true, updatable=true)
private List<ReservationDao> existingReservations;
...
}
#Entity
#Table(name="xPois")
#DiscriminatorValue("X")
#NamedQueries({
#NamedQuery(name="XPoiDao.findAll", query="SELECT p FROM XPoiDao p"),
#NamedQuery(name="XPoiDao.findByXPoiId",
query="SELECT pp FROM XPoiDao pp LEFT JOIN PoiDao p ON pp.poiId = p.poiId "
+ "LEFT JOIN ReservationDao r ON p.poiId = r.poiId WHERE pp.xPoiId = :xPoiId")
})
#ObjectTypeConverters({
#ObjectTypeConverter (
name="xPoiStatusConverter",
dataType=java.lang.String.class, // type in DB
objectType=XPoiStatusEnum.class, // Java type
conversionValues={
#ConversionValue(dataValue="FREE", objectValue="FREE"),
#ConversionValue(dataValue="OCCUPIED BY VALUE", objectValue="OCCUPIED_BY_VALUE"),
#ConversionValue(dataValue="OCCUPIED MANUALLY", objectValue="OCCUPIED_MANUALLY"),
#ConversionValue(dataValue="BLOCKED", objectValue="BLOCKED")
}
)
})
public class XPoiDao extends PoiDao implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2496267921294255723L;
// #Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private Integer id;
#Column(name="xPoiId")
private String xPoiId;
#Convert("xPoiStatusConverter")
#Column(name="status")
private XPoiStatusEnum status;
#Embedded
private ContactDao contact;
// #OneToMany(orphanRemoval=true, cascade=CascadeType.ALL, fetch=FetchType.LAZY)
// #JoinColumn(name="poiId",insertable=true,updatable=true)
// private List<ReservationDao> existingReservations;
#OneToMany(orphanRemoval=true, cascade=CascadeType.ALL, fetch=FetchType.LAZY)
#JoinColumn(name="parkingPoiId",insertable=true,updatable=true)
private List<OperatingHourDao> operatingHours;
...
}
You've got FetchType.LAZY in there. Do you get an empty list when you try to access it? Debuggers might not trigger the fetch requests.