How To Define a JPA Repository Query with a Join - java

I would like to make a Join query using Jpa repository with annotation #Query.
I have two tables:
table user
with iduser,user_name
and:
table area
with idarea, area_name and iduser
The native query is:
SELECT
u.user_name
FROM
user as u
INNER JOIN area as a ON a.iduser = u.iduser
WHERE
a.idarea = 4
Now I have a Table Hibernate entity
User and Area
So I tried with UserRespository
#Query(SELECT u.userName FROM User u
INNER JOIN Area a ON a.idUser = u.idUser
WHERE
a.idArea = :idArea)
List<User> findByIdarea(#Param("idArea") Long idArea);
The Log says:
unexpected token:
Any Idea, please?
My table Entity
#User Table
#Entity
#Table(name="user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long idUser;
private String userName;
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="iduser")
public Long getIdUser() {
return idUser;
}
public void setIdUser(Long idUser) {
this.idUser = idUser;
}
#Column(name="user_name")
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
#AREA table
#Entity
#Table(name="area")
public class Area implements Serializable {
private static final long serialVersionUID = 1L;
private Long idArea;
private String areaName;
private Long idUser;
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="idarea")
public Long getIdArea() {
return idArea;
}
public void setIdArea(Long idArea) {
this.idArea = idArea;
}
#Column(name="area_name")
public String getAreaName() {
return areaName;
}
public void setAreaName(String areaName) {
this.areaName = areaName;
}
#Column(name="iduser")
public Long getIdUser() {
return idUser;
}
public void setIdUser(Long idUser) {
this.idUser = idUser;
}
}

You are experiencing this issue for two reasons.
The JPQL Query is not valid.
You have not created an association between your entities that the underlying JPQL query can utilize.
When performing a join in JPQL you must ensure that an underlying association between the entities attempting to be joined exists. In your example, you are missing an association between the User and Area entities. In order to create this association we must add an Area field within the User class and establish the appropriate JPA Mapping. I have attached the source for User below. (Please note I moved the mappings to the fields)
User.java
#Entity
#Table(name="user")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="iduser")
private Long idUser;
#Column(name="user_name")
private String userName;
#OneToOne()
#JoinColumn(name="idarea")
private Area area;
public Long getIdUser() {
return idUser;
}
public void setIdUser(Long idUser) {
this.idUser = idUser;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Area getArea() {
return area;
}
public void setArea(Area area) {
this.area = area;
}
}
Once this relationship is established you can reference the area object in your #Query declaration. The query specified in your #Query annotation must follow proper syntax, which means you should omit the on clause. See the following:
#Query("select u.userName from User u inner join u.area ar where ar.idArea = :idArea")
While looking over your question I also made the relationship between the User and Area entities bidirectional. Here is the source for the Area entity to establish the bidirectional relationship.
Area.java
#Entity
#Table(name = "area")
public class Area {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="idarea")
private Long idArea;
#Column(name="area_name")
private String areaName;
#OneToOne(fetch=FetchType.LAZY, mappedBy="area")
private User user;
public Long getIdArea() {
return idArea;
}
public void setIdArea(Long idArea) {
this.idArea = idArea;
}
public String getAreaName() {
return areaName;
}
public void setAreaName(String areaName) {
this.areaName = areaName;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

Related

Hibernate can't create a table with #ManyToOne relation

I created a table of "User" which is perfectly created by hibernate, no problem on this one. The problem is on my second model (an entity called "Character") which is a model with a #ManyToOne relation, I don't know why but hibernate can't create this second table.
My server is a MySql instance with AWS RDS. The first table is created by hibernate but not the second.
#Entity
public class Character {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
#ManyToOne
private User joueur;
private String pseudo;
private Integer points;
public Character() {
super();
}
public Character(User joueur) {
// appel a l'autre constructeur
this(joueur, null, null);
}
public Character(User joueur, String pseudo,Integer points) {
super();
this.joueur = joueur;
this.pseudo = pseudo;
this.points = points;
}
public Integer getId() {
return id;
}
public String getPseudo() {
return pseudo;
}
public void setPseudo(String pseudo) {
this.pseudo = pseudo;
}
public Integer getPoints() {
return points;
}
public void setPoints(Integer points) {
this.points = points;
}
public User getJoueur() {
return joueur;
}
}
#Entity // This tells Hibernate to make a table out of this class
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String username;
private String password;
#OneToMany(mappedBy = "joueur")
#OrderBy("id ASC")
private List<Character> personnages;
private String league;
private Integer points;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Character> getPersonnages() {
return personnages;
}
public void setPersonnages(List<Character> personnages) {
this.personnages = personnages;
}
public String getLeague() {
return league;
}
public void setLeague(String league) {
this.league = league;
}
public Integer getPoints() {
return points;
}
public void setPoints(Integer points) {
this.points = points;
}
}
#Controller
#RequestMapping(path="/init")
public class MainController {
#Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
private UserRepository userRepository;
#Autowired
private CharacterRepository characterRepository;
#GetMapping(path="/add") // Map ONLY GET Requests
public String addNewUser () {
User joueur = new User();
joueur.setUsername("testUser");
joueur.setPassword("password");
joueur.setLeague("Bronze");
joueur.setPoints(10000);
userRepository.save(joueur);
Character perso = new Character(joueur,"testPerso1",1000);
characterRepository.save(perso);
return "";
}
#GetMapping(path="/all")
public #ResponseBody Iterable<User> getAllUsers() {
// This returns a JSON or XML with the users
return userRepository.findAll();
}
}
I have this error :
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'character add constraint Kdf2yvyvitaqt2u7de3ywfjcv foreign key (joueur_id) refe' at line 1
Ok I found the solution ... JPA annotation fordid the name of the table 'Character", just change the name of the table and it will work perfectly, stupid JPA ...

JPA Repository :Delete a row from database using native query

I want to delete a record on the basis of userId But when I run this code and execute following query it gives me an error on 404
Please Help How can I delete Data?
PropertyReport.java
#Entity
#Table(uniqueConstraints={
#UniqueConstraint(columnNames = {"reportedProperty", "reporter"})
})
public class PropertyReport implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne (cascade = CascadeType.REMOVE, fetch = FetchType.EAGER, targetEntity = Property.class)
#JoinColumn(name="reportedProperty")
private Property property;
#OneToOne
#JoinColumn(name="reporter")
private User user;
#Column(length=1024)
private String Report;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Property getProperty() {
return property;
}
public void setProperty(Property property) {
this.property = property;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getReport() {
return Report;
}
public void setReport(String report) {
Report = report;
}
}
PropertyReportReppository.java
public interface PropertyReportRepository extends JpaRepository<PropertyReport, Long>{
#Modifying
#PreAuthorize("hasAuthority('allRights')")
#Query("delete from PropertyReport pr where pr.user.id=:userId")
int deleteTenantReview(#Param ("userId") Long userId); }
API which I called
API : http://localhost:8555/api/propertyReports/search/removeByUserId/2
Please make sure your url maping is as below-
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
#RestController
public class DemoController {
#RequestMapping("/api/propertyReports/search/removeByUse‌​rId/{userId}")
public String hello(#PathVariable(value = "userId") final Long userId){
//add method call here to delete your data that you want
return "Hello World";
}
}
for more detail how to create url mapping click here

Spring JPA - Data integrity relationships

I'm new to Java and even more newer to Spring (Boot and JPA) but I was curious, I'm trying to debug an issue that says, "No identifier specified for entity".
For illustartion purposes, I've created the following tables from this diagram:
Originally, there was a M:N relationship between the user and vehicle table, so I created an associative entity (UserVehicleAsso) to split the two up. I was following this guide on M:N mapping in Java, http://viralpatel.net/blogs/hibernate-many-to-many-annotation-mapping-tutorial/
For the most part, it was pretty straight forward but my question is, within the associative entity (UserVehicleAsso), do I have to use the #Id annotation for each of the foreign keys? I assume that I didn't need to because those were automatically generated from each of the respective tables.
Let me know your thoughts or comments, thanks.
Also, below is the code that I used to generate these models:
For the User table/class:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int userId;
private String fName;
private String lName;
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(name="userVehicleAsso",
joinColumns={#JoinColumn(name="userID")},
inverseJoinColumns={#JoinColumn(name="vehicleID")})
private Set<Vehicle> vehicles = new HashSet<Vehicle>();
//constructor
protected User() {}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getFName() {
return fName;
}
public void setFName(String fName) {
this.fName = fName;
}
public String getLName() {
return lName;
}
public void setLName(String lName) {
this.lName = lName;
}
public Set<Vehicle> getVehicles() {
return vehicles;
}
public void setVehicles(Set<Vehicle> vehicles) {
this.vehicles = vehicles;
}
#Override
public String toString() {
return getFName() + "," + getLName();
}}
For the Vehicle table/class:
#Entity
public class Vehicle {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int vehicleId;
private String brand;
private String model;
//foreign key mappings
//mapping with associative
#ManyToMany(mappedBy="vehicles")
private Set<User> users = new HashSet<User>();
//constructors
protected Vehicle() {}
public Vehicle(int id) {
this.vehicleId = id;
}
public Vehicle (String brand, String model) {
this.brand = brand;
this.model = model;
}
/* public Vehicle() {
}*/
public int getVehicleId() {
return vehicleId;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public void setVehicleId(int vehicleId) {
this.vehicleId = vehicleId;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
#Override
public String toString() {
// + setBodyType() + "," +
return getBrand() + "," + getModel();
}
}
And then finally, my associtive table/class:
#Entity
public class UserVehicleAsso{
private int userID;
private int vehicleID;
public int getUserID() {
return userID;
}
public void setUserID(int userID) {
this.userID = userID;
}
public int getVehicleID() {
return vehicleID;
}
public void setVehicleID(int vehicleID) {
this.vehicleID = vehicleID;
}
}
In my opinion, it's not necessary to have an Entity class for the middle table in your case. The table will be generated automatically if configured correctly. In this table, there would not be column ID, only two columns with userID and vehicleID data.
Now, if your middle table has more than what are needed to establish the M:N relationship, then your middle Entity class is needed, and the ID of it, too. For example, if this class is intended to store the time stamp every time a relationship is established, you have to:
Create this Entity class,
Give it an ID field with proper generation strategy,
Map the time stamp with a field with adequate type, annotation/XML mapping and so on.
This part of JPA/Hibernate have confused me a lot and I used to get into them. If my memory serves me well this is the proper/perfect way how things should work.
You can specify a composite primary key class that is mapped to multiple fields or properties of the entity.
Here are sample codes:
public class ActivityRegPK implements Serializable {
private int activityId;
private int memberId;
public int getActivityId() {
return activityId;
}
public void setActivityId(int activityId) {
this.activityId = activityId;
}
public int getMemberId() {
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
}
associtive table/class:
#IdClass(ActivityRegPK.class)
#Entity
#Table(name="activity_reg")
#NamedQuery(name="ActivityReg.findAll", query="SELECT a FROM ActivityReg a")
public class ActivityReg implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="activity_id")
private int activityId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="ins_date")
private Date insDate;
#Id
#Column(name="member_id")
private int memberId;
}
Activity.class
#Entity
#NamedQuery(name="Activity.findAll", query="SELECT a FROM Activity a")
public class Activity implements Serializable {
// some attributes
}

Spring Data JPA user posts

I have user login and profile view, I would like the users to have posts. Can someone guide me in the right direction?
I have a user entity:
#Entity
#Table(name = "usr", indexes = { #Index(columnList = "email", unique = true) })
// using usr because in may conflict with the name of the class
public class User {
public static final int EMAIL_MAX = 250;
public static final int NAME_MAX = 50;
/*
* public static enum Role {
*
* UNVERIFIED, BLOCKED, ADMINISTRATOR
*
* }
*/
// primary key long, needs to be annotated with #Id
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
// add columns
#Column(nullable = false, length = EMAIL_MAX)
private String email;
#Column(nullable = false, length = NAME_MAX)
private String name;
// no length, the password will be encrypted to some longer value than the
// user enters
#Column(nullable = false)
private String password;
/*
* //email verification code
*
* #Column(length = 16) private String verificationCode;
*
* public String getVerificationCode() { return verificationCode; }
*
* public void setVerificationCode(String verificationCode) {
* this.verificationCode = verificationCode; }
*
*
* #ElementCollection(fetch = FetchType.EAGER) private Set<Role> roles = new
* HashSet<Role>();
*
*
*
* public Set<Role> getRoles() { return roles; }
*
* public void setRoles(Set<Role> roles) { this.roles = roles; }
*/
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEditable() {
User loggedIn = MyTools.getSessionUser();
if (loggedIn == null) {
return false;
}
return loggedIn.getId() == id;
}
}
and repo:
public interface UserRepository extends JpaRepository<User, Long> {
// #Query("select u from User u where u.email = ?1")
User findByEmail(String email);
}
now, in order to have posts by that user, do I create a posts entity and repository with #manytoone in post pojo?
I'm trying to make a twitter eventually but first I gotta get users to post. If you know of a good tutorial explaining this then that'd be great.
Create a second entity (java class) e.g. UserPost:
#Entity
#Table(...)
public class UserPost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private long userId;
...
}
Then add #OneToMany relationship field to User. Cascading, lazy-loading, etc. depends on how you'd use it. It'd look like this inside User:
#OneToMany(cascade={...})
#JoinColumn(name="userId")
private Set<UserPost> posts;

Column specified twice using EntityManager

I'm trying to persist an entity that has a composite primary key but I get error :
12:59:48,221 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-56) SQL Error: 1110, SQLState: 42000
12:59:48,221 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-56) Column 'SENDERID' specified twice
I'm using EntityManager so I'm not sure where the 'SENDERID' is speciefied twice?
This is all the relevant classes:
Webservice:
#Path("friendservice")
public class FriendWebService {
#EJB
private FriendrequestFacade friendRequestFacade;
#GET
#Path("friendrequest")
#Produces(MediaType.TEXT_PLAIN)
public String insertFriendRequest(
#Context HttpServletRequest request){
String result = "false";
User user = (User) request.getSession().getAttribute("user");
User otherUser = (User) request.getSession().getAttribute("profileuser");
if((user != null) && (otherUser != null)){
if(user.getId() != otherUser.getId()){
System.out.println("Both users are alive.");
if(friendRequestFacade.insertFriendRequest(user, otherUser))
result = "true";
}
}
return result;
}
}
Facade:
#Stateless
public class FriendrequestFacade extends AbstractFacade<Friendrequest> {
#PersistenceContext(unitName = "FakebookPU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public FriendrequestFacade() {
super(Friendrequest.class);
}
public boolean insertFriendRequest(User user, User otherUser){
Friendrequest fr = new Friendrequest();
FriendrequestPK frPK = new FriendrequestPK();
frPK.setSenderid(user.getId());
frPK.setReceiverid(otherUser.getId());
fr.setId(frPK);
em.clear();
em.persist(fr);
return true;
}
}
Entity:
#Entity
#XmlRootElement
#Table(name="FRIENDREQUEST")
#NamedQuery(name="Friendrequest.findAll", query="SELECT f FROM Friendrequest f")
public class Friendrequest implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private FriendrequestPK id;
#Temporal(TemporalType.TIMESTAMP)
private Date senddate;
//bi-directional many-to-one association to User
#ManyToOne
#JoinColumn(name="SENDERID")
private User user1;
//bi-directional many-to-one association to User
#ManyToOne
#JoinColumn(name="RECEIVERID")
private User user2;
public Friendrequest() {}
public FriendrequestPK getId() {
return this.id;
}
public void setId(FriendrequestPK id) {
this.id = id;
}
public Date getSenddate() {
return this.senddate;
}
public void setSenddate(Date senddate) {
this.senddate = senddate;
}
public User getUser1() {
return this.user1;
}
public void setUser1(User user1) {
this.user1 = user1;
}
public User getUser2() {
return this.user2;
}
public void setUser2(User user2) {
this.user2 = user2;
}
}
Composite Key:
#Embeddable
public class FriendrequestPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#Column(insertable=false, updatable=false)
private int senderid;
#Column(insertable=false, updatable=false)
private int receiverid;
public FriendrequestPK() {}
public FriendrequestPK(int senderid, int receiverid){
this.senderid = senderid;
this.receiverid = receiverid;
}
public int getSenderid() {
return this.senderid;
}
public void setSenderid(int senderid) {
this.senderid = senderid;
}
public int getReceiverid() {
return this.receiverid;
}
public void setReceiverid(int receiverid) {
this.receiverid = receiverid;
}
}
What am I doing wrong?
First of all please let me clarify that I rarely use #EmbeddedId so I could be missing something. That being told, the error is telling you that SENDERID column is specified twice: first time in your entity and then in the composite key. The same is probably happening with RECEIVERID too.
Entity
public class Friendrequest implements Serializable {
...
#EmbeddedId
private FriendrequestPK id;
#ManyToOne
#JoinColumn(name="SENDERID") // Column = SENDERID
private User user1;
#ManyToOne
#JoinColumn(name="RECEIVERID") // Column = RECEIVERID
private User user2;
...
}
Composite key
public class FriendrequestPK implements Serializable {
...
#Column(insertable=false, updatable=false)
private int senderid; // Column = SENDERID
#Column(insertable=false, updatable=false)
private int receiverid; // Column = RECEIVERID
...
}
According to Mapping identifier properties section in Hibernate Annotations reference guide, the entity mapping should be done using #MapsId annotation:
public class Friendrequest implements Serializable {
...
#EmbeddedId
private FriendrequestPK id;
#MapsId("senderid") // senderid = Field in FriendrequestPK class
#ManyToOne
private User user1;
#MapsId("receiverid") // receiverid = Field in FriendrequestPK class
#ManyToOne
private User user2;
...
}

Categories

Resources