Error in sqlException when attempting to use generated named query - java

I have created a bean:
package beans;
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import mazeJPA.Forumcategory;
/**
* Session Bean implementation class ForumBean
*/
#Stateless
#LocalBean
public class ForumBean
{
#PersistenceContext(unitName = "mazeEJB")
private EntityManager em;
/**
* Default constructor.
*/
public ForumBean(){}
public List<Forumcategory> getCategories()
{
return em.createNamedQuery
(
"Forumcategory.findAll", Forumcategory.class
).getResultList();
}
}
and its entity class
package mazeJPA;
import java.io.Serializable;
import javax.persistence.*;
/**
* The persistent class for the forumcategory database table.
*
*/
#Entity
#Table(name="forumcategory")
#NamedQuery(name="Forumcategory.findAll", query="SELECT f FROM Forumcategory f")
public class Forumcategory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int cid;
private String desc;
private String name;
public Forumcategory() {
}
public int getCid() {
return this.cid;
}
public void setCid(int cid) {
this.cid = cid;
}
public String getDesc() {
return this.desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
When I call getCategories() from my servlet I get an sql exception:
Internal Exception:
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 'DESC, NAME FROM
forumcategory' at line 1 Error Code: 1064 Call: SELECT CID, DESC, NAME
FROM forumcategory Query: ReadAllQuery(name="Forumcategory.findAll"
referenceClass=Forumcategory sql="SELECT CID, DESC, NAME FROM
forumcategory")
My table is:
cid INT NOT NULL, name VARCHAR(255) NOT NULL, desc TEXT NOT NULL,
PRIMARY KEY (cid)
I don't know why this is happening. Have I got something wrong with the mapping? I have only recently added this to my project is that anything to do with it i.e. do I have to generate all the tables at once?

DESC is a reserved sql word, so you have to scape it, using desc, for example
SELECT CID, `DESC`, NAME FROM ...

DESC is a reserved keyword in most SQL. Seems that your JPA provider doesn't automatically escape these for you (surround in quotes). Some JPA implementations (e.g DataNucleus JPA) do that for you.

Related

How do I get the name of the audited table in RevisionInfo using Envers?

Intending to get the name of the table that was audited. Hopefully maybe by taking the object which is sent to revision info before it writes. Is there a way to do that.
#Entity
#RevisionEntity
#Table(name = "revision_info")
public class revision_info{
#Column(name = "tableName", length=36)
private String tableName=getTableName();
public revision_info() {
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}

Display some columns in Vaadin grid with JPA

I created Entity class:
package order;
import javax.persistence.*;
import java.time.LocalDate;
import java.util.UUID;
#Entity
#Table(name = "bo_order")
public class Order {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String login;
private Long internalNumber;
private String food;
#Column(name="data_ins")
private LocalDate dateOfOrder;
private String orderNumber;
public Order(){}
public Order(String login)
{
this.login = login;
}
public Order(String login, Long internalNumber, String food, LocalDate dateOfOrder) {
this.login = login;
this.internalNumber = internalNumber;
this.food = food;
this.dateOfOrder = dateOfOrder;
}
public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
}
public String generateOrderNumber()
{
return UUID.randomUUID().toString();
}
#Override
public String toString() {
return "Order{" +
"id=" + id +
", login='" + login + '\'' +
", internalNumber=" + internalNumber +
", food='" + food + '\'' +
", dateOfOrder=" + dateOfOrder +
'}';
}
}
added Repository to this:
package order;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface OrderRepository extends CrudRepository<Order, Long>{
List<Order> findByLogin(String login);
#Query(value="SELECT id, login FROM bo_order", nativeQuery = true)
public List<Order> findAllPurchasers();
}
and try to display values from #Query in Grid:
package purchasers;
import com.vaadin.annotations.Title;
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.*;
import order.Order;
import order.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
#SpringUI(path = "/allpurchasers")
#Title("All today's purchasers")
public class AllPurchasersGUI extends UI {
#Autowired
private final OrderRepository orderRepository;
final Grid<Order> grid;
public AllPurchasersGUI(OrderRepository pr) {
this.orderRepository = pr;
grid = new Grid<>(Order.class);
grid.setSizeFull();
}
#Override
protected void init(VaadinRequest vaadinRequest) {
setContent(grid);
listPurchasers();
}
private void listPurchasers()
{
grid.setItems(orderRepository.findAllPurchasers());
}
}
but I got an error org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute query; SQL [SELECT id, login FROM bo_order]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query and then
Caused by: org.postgresql.util.PSQLException: The column name data_ins was not found in this ResultSet.
I know data_ins is not in ResultSet because I don't want it there. I can display all values in Grid from bo_order with findAll but I want just id and login. How can I achive this? I also tried to make List<Object> instead of List<Order> but then I got problem with displaying then.
TL;DR: Add grid.setColumns("id", "login") to the end of the listPurchasers() method or include data_ins in the list of database columns in the #Query annotation.
When you create a Grid with the Grid(Class<T> beanType) constructor, one column will be added for every getter in the bean type. This will lead to an error unless data for all those getters are also loaded from the database.
In this case, the #Query annotation defines that data should only be fetched from the database for the columns id and login. The exception you get refers to the database column data_ins, which seems to be mapped to the dateOfOrder bean property, but I don't see any code that would remove the automatically added column for that property.
The easiest way of ensuring only desired columns are used by your grid is to use the setColumns method. That method works like setColumnOrder, except that it also removes any column that isn't included as a parameter.
Alternatively, you can also change your #Query annotation to also include the data_ins property from the database if you actually want that data to be shown as a column in the grid.
Grid takes parameters from Order class, so if there were many getters then they were displayed in columns. I did:
private void listPurchasers()
{
List<Order> allOrders = (List<Order>) orderRepository.findAll();
grid.setItems(allOrders);
grid.setColumnOrder("id", "login", "dateOfOrder");
grid.removeColumn("food");
}
so it seems to be very easy to add/remove columns to display.

Updating primary key for spring boot entity manager jpa

i need to update tow columns inside my table (Job this table is joint with two other tables employees and job-history)one of them is the primary key, but i get error, if someone can help.
package com.touati.org.model;
import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.List;
/**
* The persistent class for the jobs database table.
*
*/
#Entity
#Table(name="jobs")
#NamedQuery(name="Job.findAll", query="SELECT j FROM Job j")
public class Job implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="JOB_ID")
private String jobId;
#Column(name="JOB_TITLE")
private String jobTitle;
#Column(name="MAX_SALARY")
private BigDecimal maxSalary;
#Column(name="MIN_SALARY")
private BigDecimal minSalary;
//bi-directional many-to-one association to Employee
#OneToMany(mappedBy="job")
private List<Employee> employees;
//bi-directional many-to-one association to JobHistory
#OneToMany(mappedBy="job")
private List<JobHistory> jobHistories;
public Job() {
}
public String getJobId() {
return this.jobId;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public String getJobTitle() {
return this.jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
public BigDecimal getMaxSalary() {
return this.maxSalary;
}
public void setMaxSalary(BigDecimal maxSalary) {
this.maxSalary = maxSalary;
}
public BigDecimal getMinSalary() {
return this.minSalary;
}
public void setMinSalary(BigDecimal minSalary) {
this.minSalary = minSalary;
}
public List<Employee> getEmployees() {
return this.employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public Employee addEmployee(Employee employee) {
getEmployees().add(employee);
employee.setJob(this);
return employee;
}
public Employee removeEmployee(Employee employee) {
getEmployees().remove(employee);
employee.setJob(null);
return employee;
}
public List<JobHistory> getJobHistories() {
return this.jobHistories;
}
public void setJobHistories(List<JobHistory> jobHistories) {
this.jobHistories = jobHistories;
}
public JobHistory addJobHistory(JobHistory jobHistory) {
getJobHistories().add(jobHistory);
jobHistory.setJob(this);
return jobHistory;
}
public JobHistory removeJobHistory(JobHistory jobHistory) {
getJobHistories().remove(jobHistory);
jobHistory.setJob(null);
return jobHistory;
}
}
my controller: here when i try to look for all job in the data base it works fine, also if i try to update juste the title of the job it works fine to but in case that i try to set a new primary key for the job table it gives me error here my controller.
package com.touati.org.model;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
#Controller // This means that this class is a Controller
#RequestMapping(path="/project") // This means URL's start with /demo (after Application path)
public class MainController {
#GetMapping(path="/job")
public #ResponseBody Iterable<Job> getAllJob() {
// This returns a JSON or XML with the users
return jobRepository.findAll();
}
#GetMapping(path="/job/{jobId}")
public #ResponseBody String getJob(#PathVariable String jobId) {
Job job = jobRepository.findOne(jobId);
try {
job.setJobTitle("manager");
job.setJobId("test1");
jobRepository.save(job);
}
catch (Exception ex) {
return "Error updating the job: " + ex.toString();
}
return "Job succesfully updated!";
}
}
i got this error,
Error updating the user: org.springframework.orm.jpa.JpaSystemException: identifier of an instance of com.touati.org.model.Job was altered from test to test1; nested exception is org.hibernate.HibernateException: identifier of an instance of com.touati.org.model.Job was altered from test to test1
Thank you for your help.
Primary key should never be changed. If you need to change primary key it means your design is bad. If you need to change JOB_ID often then create another column for your primary key like ID. Another possibility is to copy all attributes and create new record with new JOB_ID and then remove old one.

Join two tables and send as one record

Suppose, that we have such tables:
Table Users
iduser | password
Table Marks
id | iduser | mark | idtest
Table Tests
idtest | title
Query looks like this:
#GET
#Path("/{id}/marks")
#Produces(MediaType.APPLICATION_JSON)
public Object funkcja(#PathParam("id") Integer iduser) {
Query query = em.createQuery("select m,t from Marks m, Tests t where m.idusers=:iduser and m.idtest = t.idtests");
query.setParameter("iduser", id);
List<Object> results = (List<Object>)query.getResultList();
return results;
}
I have entity classes:
Marks , Users, Tests
What I should to do in order to join tables and send JSON type on web service and how to convert JSON to entity class because I would like to show in TableView.
Perhaps there are other simple ways?
Maybe map or JsonObject?
You seem to have multiple questions here; I think you need to break these down into separate questions.
For the "main" question, which is about JPA and how to join the entities, I would do that at the entity level, not at the query level. I.e. I think I would have entity classes like:
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="Tests")
public class Test {
#Id
#Column(name="idtest")
private int id ;
private String title ;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Override
public boolean equals(Object other) {
if (other instanceof Test) {
return Objects.equals(title, ((Test)other).title);
} else return false ;
}
#Override
public int hashCode() {
return Objects.hash(title);
}
}
and then the Mark entity can use a #ManyToOne annotation to reference the actual Test object (not its id):
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name="Marks")
public class Mark {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id ;
#ManyToOne
#JoinColumn(name="idtest")
private Test test ;
// You probably don't want a reference to User here, as the User class
// encapsulates the password, which you don't want to throw back and
// forward across the network unnecessarily. But if the User class
// instead had a user name etc you wanted, you could use the same
// #ManyToOne technique to reference a User object here if you needed.
#Column(name="iduser")
private int userId ;
private int mark ;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public Test getTest() {
return test;
}
public void setTest(Test test) {
this.test = test;
}
public int getMark() {
return mark;
}
public void setMark(int mark) {
this.mark = mark;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Mark) {
Mark other = (Mark)obj ;
return Objects.equals(userId, other.userId)
&& Objects.equals(test, other.test)
&& mark == other.mark ;
} else return false ;
}
#Override
public int hashCode() {
return Objects.hash(userId, test, mark);
}
}
Now your query looks like
TypedQuery<Mark> query = em.createQuery("select m from Mark m where m.userId=:userid");
query.setParameter("userid", iduser);
List<Mark> results = query.getResultList();
and the Mark instances in the list already have all the data you need:
for (Mark mark : results) {
System.out.println(mark.getTest().getTitle() + ": " + mark.getMark());
}
For the remaining questions:
Assuming you have a server set up with a JAX-RS implementation (e.g. Jersey) the code snippet you showed (modified with the new query) should generate JSON output. (You can use a developer tool such as Firefox REST client to view the JSON output by specifying the appropriate URL and request headers, and viewing the response.)
On the client (JavaFX) side you can use Jersey's client library (or maybe Apache HttpComponent library) to create the web requests easily, and a library such as GSON or Jackson for mapping the JSON content you get back to a Java object for display in the TableView.
I recommend trying this and asking specific questions about the remaining pieces if you get stuck.

Spring mvc restful - wrong json reply format

There is a little problem in replying on ajax requests. Initially, I have simplest restful service, based on spring boot MVC.
model:
import javax.persistence.*;
import java.util.*;
#Entity
#Table(name = "testmodel")
public class TestModel
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)//Postgresql sequence generator
private long id;
#Column(name = "name")
private String name;
#Column(name = "content")
private String content;
//Constructor
public TestModel()
{
}
//Id getter
public long getId()
{
return this.id;
}
//Name getter-setter
public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name = name;
}
//Content getter-setter
public String getContent()
{
return this.content;
}
public void setContent(String content)
{
this.content = content;
}
}
DAO for model:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.*;
public interface TetsModelDAO extends JpaRepository<Samples, Long>
{
#Query("SELECT s FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name")
List<TestModel> fetchByNameEntry(#Param("entry") String entry);
}
Controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
#RequestMapping("/")
public class TestController
{
#Autowired
private TetsModelDAO testmodel;
#RequestMapping("/name")
public List<TestModel> getDatasetsByNameEntry(#RequestParam("entry") String entry)
{
return testmodel.fetchByNameEntry("%"+entry+"%");
}
}
Client-side ajax request:
$.ajax(
{
url : "/name?entry=", //get all records
method: "GET"
})
This example works perfectly - stringified reply looks like standart json structure:
{"id":"1", "name":"John", "content":"blablabla1"}
{"id":"2", "name":"Sam", "content":"blablabla2"}
{"id":"3", "name":"Ken", "content":"blablabla3"}
However, when I tried to define fileds in JPQL query explicitly (fetch, say, only id and name fields), I get wrong result in reply.
DAO with modified query (other code without changes):
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.*;
public interface TetsModelDAO extends JpaRepository<Samples, Long>
{
#Query("SELECT s.id, s.name FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name")
List<TestModel> fetchByNameEntry(#Param("entry") String entry);
}
In this case reply looks like this:
1, John, 2, Sam, 3, Ken
How to resolve this problem gracefully (without creating "helper classes")?
You can return DTO directly from Repository:
public interface TetsModelDAO extends JpaRepository<Samples, Long>
{
#Query("SELECT new mypackage.TestDto(s.id, s.name) FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name")
List<TestDto> fetchByNameEntry(#Param("entry") String entry);
}
where TestDto contains only required fields:
package mypackage;
public class TestDto {
private final long id;
private final String name;
public TestDto(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}
Your query doesn't return instances of TestModel. It returns arrays of objects (i.e. a List<Object[]>), each array containing the ID and the name of a found TestModel. The correct query is
SELECT s FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name
You'd better implement automated tests to check that your DAO queries return what they should.

Categories