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.
Related
I'm trying to implement entity auditing in my Java Spring Boot project using spring-data-envers. All the entities are being created as they should, but I've come up against a brick wall when executing the query.
parentRepository.findRevisions(id).stream().map(Parent::getEntity).collect(Collectors.toList());
During this select the repository is supposed to fetch info also from the child entity, instead I get unable to find <child object> with {id}.
According to my experiments categoryId is being searched in the Category_Aud table, instead of the actual table with desired data.
Code snippets:
#Data
#Entity
#Audited
#NoArgsConstructor
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Enumerated(EnumType.STRING)
private Status status;
#Enumerated(EnumType.STRING)
private Type requestType;
private String fullName;
#ManyToOne
#JoinColumn(name = "child_id")
private Child child;
}
#Data
#Entity
#Audited
#NoArgsConstructor
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
}
I've extended Parent with RevisionRepository
#Repository
public interface ParentRepository extends RevisionRepository<Parent, Long, Long>, JpaRepository<Parent, Long>
And annotated my SpringBootApplication entry class with:
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
I couldn't find any explanation for this so far, how can make parentRepository get what I need?
The underlying problem here is that the reference from a versioned entity isn't really properly defined. Which variant of the reference should be returned? The one at the start of the version you use as a basis, the one at the end? The one that exists right now?
There are scenarios for which each variant makes sense.
Therefor you have to query the revisions yourself and can't simply navigate to them.
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
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.
I have 2 entity classes with one-to-one dependencies on their primary keys:
The primary table:
#Entity
#Table(name = "tablePrimary")
#XmlRootElement
//...
public class TablePrimary implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#Column(name = "code")
private String code;
// set the dependency of table2 to this class
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Table2 table2inst;
// ...
} // end of class TablePrimary
The dependent table:
#Entity
#Table(name = "table2")
#XmlRootElement
//...
public class Table2 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#Column(name = "name")
private String name;
#MapsId
#OneToOne(mappedBy = "table2inst")
#JoinColumn(name = "id")
private TablePrimary tablePrimaryInst;
//...
} // end of class Table2
Whenever there is a row with say, id==55 in TablePrimary, there is
a row with the same id==55 in Table2 and vice-versa.
So in essence, these two tables are one table in logical level-- split into 2 physical tables for practicality.
When i'm inserting a row into the "logical" table,
i first am inserting to TablePrimary-- the primary table in the relationship,
getting the value of id==55 field of this new row i just inserted and inserting a row to
Table2 with that id value.
As part of this, i'm checking, just in case,
whether a row with id==55 is already in Table2.
Is there a better way of doing this?
Does JPA have a feature to make these two insertions to these two physical tables
by using the 1-1 dependency I configured on them-- without me having to do it "manually" in the code? Or a control feature on the id fields of the tables I set the dependency on?
If there is-- how is done? how does it handle the key value collision in the dependent table-- Table2?
A similar thing will come up on deletion. However, i'm not there yet, and might figure out out of this.
TIA.
You can take advantage of JPA cascading. You will have to define a cascade on the owning side (the one with the join column). If you have set the owning side of the relationship and persist the owning side, the inverse side will be persisted as well:
TablePrimary tp = new TablePrimary();
Table2 t2 = new Table2();
t2.setTablePrimaryInst(tp);
entityManager.persist(t2);
The 'mappedBy' element is supposed to be placed on the inverse side. You entities could look like this:
public class Table2 ...
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "tp_id")
private TablePrimary tablePrimary;
public class TablePrimary...
#OneToOne(mappedBy="tablePrimary")
private Table2 table2;
I am facing a proble that put me in difficult situation.
I have class Article:
#Entity
#Table(name = "Articles")
public class Article implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="article_id")
private Long id;
#Column(name="a_name")
private String name;
#Column(name="a_content")
private String content;
#OneToMany
#Column(name="a_tag")
private Collection <Tags> tag;
#Entity
#Table(name = "Tags")
public class Tags implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="tag_id")
private Long tag_id;
#Column(name="tag_name",nullable=false)
private String tag_name;
#Column(name="tag_descr")
private String tag_descr;
//position 0 - supertag
//position 1 - subsupertag
//position 2 - subtags
//Collection limited to 3 elements.(3 tags at most, necessaryly Super,subsuper,subtag
#Column(name="super_tags")
#OneToMany
private Collection<Tags> supertags = new ArrayList<Tags>(3);
//0-supertag 1-subsupertag 2- subtags
#Column(name="tag_type")
private int tag_type;
My tagging system is such that I have Supertag, subsuprttag and subtag. Supertag is parent for subsupertag and subtag, subsupertag is parent for subtag.
Each article has super, subsuper and sub tags.
Now, I want to get only articles from database, that has a certain tag, but have no idea how to refere to , for example, element 2 in Collection tags (by name or position), (which would be subtag).
final String q = "SELECT f FROM Article f WHERE f.a_tag= ..I m lost here ...
EntityManager em;
em.createQuery(q).getResultList();
I hope my question is clear enough. I gave it my best shot)) Thank you.
You can join to the tags to access them in JPQL,
see,
http://en.wikibooks.org/wiki/Java_Persistence/JPQL#JOIN
As for the type of Tag, how is the type stored in the database?