when trying a search on some entities in the CRUD module of Play I'm getting this exception:
play.exceptions.JavaExecutionException: org.hibernate.exception.SQLGrammarException: could not execute query
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:290)
at Invocation.HTTP Request(Play!)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1235)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:250)
at play.db.jpa.JPAPlugin$JPAModelLoader.fetch(JPAPlugin.java:431)
at controllers.CRUD$ObjectType.findPage(CRUD.java:253)
at controllers.CRUD.list(CRUD.java:36)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:413)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:408)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:182)
... 1 more
Caused by: org.hibernate.exception.SQLGrammarException: could not execute query
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.loader.Loader.doList(Loader.java:2452)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2192)
at org.hibernate.loader.Loader.list(Loader.java:2187)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:452)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:363)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1258)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:241)
... 7 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'CHARSET' in 'where clause'
at com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
at com.mysql.jdbc.Util.getInstance(Util.java:384)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1054)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3566)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3498)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2113)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2568)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2113)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2275)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1869)
at org.hibernate.loader.Loader.doQuery(Loader.java:718)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:270)
at org.hibernate.loader.Loader.doList(Loader.java:2449)
... 15 more
The odd thing is that search works for some entities and not for others. For example, for the following entity adding any string in the search box works:
#Entity
public class Act extends Model {
#Transient
private static final int PAGE_SIZE = Integer.parseInt(Play.configuration.getProperty("pagination.size","10"));
#Required(message = "act.name.required")
public String name;
#Required(message = "act.description.required")
#Lob
#MaxSize(value=500, message="act.description.maxsize")
public String description;
public Blob image;
public boolean showInClosedMode;
#Temporal(TemporalType.TIMESTAMP)
public Date updated;
#Required(message = "act.theatre.required")
#ManyToOne
public Theatre theatre;
public boolean disabled;
#OneToMany(mappedBy="act")
public List<Offer> offers;
#ManyToMany(cascade=CascadeType.PERSIST)
public Set<Tag> tags;
#Transient
public String tagListSupport;
[... some methods ...]
}
But not for this one:
#Entity
public class User extends Model {
#Required(message = "user.name.required")
public String name;
#Email(message = "user.email.invalid")
public String email;
public String prefLang;
public Long prefCity;
public int credits;
public Date lastLogin;
#NoBinding("profile")
public boolean disabled;
#NoBinding("profile")
public boolean admin;
#NoBinding("profile")
public boolean anonymous;
#OneToMany(mappedBy = "owner")
public List<Ticket> tickets;
#ManyToMany
public List<Theatre> theatres;
public String googleId;
public String yahooId;
public String facebookId;
public String twitterId;
public String twitter_token;
public String twitter_secret;
public String username;
public String password;
#OneToMany(mappedBy = "user")
public List<Event> history;
[...Methods...]
}
Any idea why this happens?
My guess is the database you are using does not like you having a table named "user" which is what you get when you don't provide a specific name for your table. I know that Postgres does not allow for a "user" table because "user" is a keyword. I'm not sure for MySQL. Try adding the javax.persistence.Table annotation after your #Entity annotation in the User class:
#Entity
#Table(name = "my_user")
public class User extends Model {
...
}
where you give it a whatever name you want that is not "user". Alternatively (but not tested) you may be able wrap the "user" name in quotes:
#Entity
#Table(name = "\"user\"")
public class User extends Model {
...
}
Be careful with column names.
2012-08-08T12:58:29+00:00 app[web.1]: 12:58:29,513 ERROR ~ Unsuccessful: create table users (id int8 not null, email varchar(255), enabled bool not null, name varchar(255), user varchar(255), primary key (id))
2012-08-08T12:58:29+00:00 app[web.1]: 12:58:29,514 ERROR ~ ERROR: syntax error at or near "user"
That was my case, changing column "user" to "userId" solved my issue
Related
I'm having trouble with a many to many relation with JPA.
My code looks as follows:
The Sensor class:
#Entity
#Table(name = "sensor")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Sensor {
#Id
private long chipId;
#OneToMany(mappedBy = "sensor")
#JsonBackReference
private Set<Link> userLinks;
private String firmwareVersion;
private long creationTimestamp;
private String notes;
private long lastMeasurementTimestamp;
private long lastEditTimestamp;
private double gpsLatitude;
private double gpsLongitude;
private double gpsAltitude;
private String country;
private String city;
private boolean indoor;
private boolean published;
}
The user class:
#Entity
#Table(name = "user")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonManagedReference
private int id;
private String firstName;
private String lastName;
private String email;
private String password;
#OneToMany(mappedBy = "user")
private Set<Link> sensorLinks;
private int role;
private int status;
private long creationTimestamp;
private long lastEditTimestamp;
}
And the Link class (relation class):
#Entity
#Table(name = "link")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Link {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name = "user_id")
#MapsId("user_id")
private User user;
#ManyToOne
#JoinColumn(name = "sensor_id")
#MapsId("sensor_id")
private Sensor sensor;
private boolean owner;
private String name;
private int color;
private long creationTimestamp;
}
The controller:
...
#RequestMapping(method = RequestMethod.GET, path = "/user/{email}", produces = MediaType.APPLICATION_JSON_VALUE)
#ApiOperation(value = "Returns details for one specific user")
public User getUserByEmail(#PathVariable("email") String email) {
return userRepository.findByEmail(email).orElse(null);
}
...
The UserRepository:
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByEmail(String email);
#Modifying
#Query("UPDATE User u SET u.firstName = ?2, u.lastName = ?3, u.password = ?4, u.role = ?5, u.status = ?6 WHERE u.id = ?1")
Integer updateUser(int id, String firstName, String lastName, String password, int role, int status);
}
I want to achieve, that the user endpoint shows all linked sensors with that particular user.
What I get is only an error message:
JSON mapping problem:
com.chillibits.particulatematterapi.model.db.main.User["sensorLinks"];
nested exception is
com.fasterxml.jackson.databind.JsonMappingException: Infinite
recursion (StackOverflowError) (through reference chain:
com.chillibits.particulatematterapi.model.db.main.User["sensorLinks"])
How can I fix this issue?
Thanks in advance
Marc
------------------------------------ Edit -----------------------------------
According to Abinash Ghosh's answer, I added following DTOs:
UserDto:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class UserDto {
private int id;
private String firstName;
private String lastName;
private Set<LinkDto> sensorLinks;
private int role;
private int status;
private long creationTimestamp;
private long lastEditTimestamp;
}
LinkDto:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class LinkDto {
private Integer id;
private SensorDto sensor;
private boolean owner;
private String name;
private int color;
private long creationTimestamp;
}
And the mapper (I realized it a bit different, but it should be the same):
public UserDto getUserByEmail(#PathVariable("email") String email) {
User user = userRepository.findByEmail(email).orElse(null);
return convertToDto(user);
}
private UserDto convertToDto(User user) {
return mapper.map(user, UserDto.class);
}
This leads to following Exception:
2020-04-13 14:22:24.383 WARN 8176 --- [nio-8080-exec-2] o.h.e.loading.internal.LoadContexts : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext#68ab57c7<rs=HikariProxyResultSet#2017009664 wrapping Result set representing update count of -1>
1) Error mapping com.chillibits.particulatematterapi.model.db.main.User to com.chillibits.particulatematterapi.model.io.UserDto
1 error] with root cause
java.lang.StackOverflowError: null
at com.mysql.cj.NativeSession.execSQL(NativeSession.java:1109) ~[mysql-connector-java-8.0.19.jar:8.0.19]
...
It's working!
This post helped: https://stackoverflow.com/a/57111004/6296634
Seems that you should not use Lombok #Data in such cases.
When User serialized for the response, all getter methods of User's fields are called.
So, User relational field sensorLinks's getter are also called to set value. This happened recursively. That's cause of infinite recursion.
It's better to not use Entity as a response. Create a DTO class for User then map User entity value into DTO then send response. Don't use any Enity class again into DTO then it will result same problem
For dynamically map one model to another you can use ModleMapper
public class UserDTO {
//Fields you want to show in response & don't use enity class
private Set<LinkDTO> sensorLinks;
}
public class LinkDTO{
//Fields you want to show in response &don't use enity class
}
public User getUserByEmail(#PathVariable("email") String email) {
User user = userRepository.findByEmail(email).orElse(null);
UserDTO userDto = merge(user,UserDTO.class)
return userDto;
}
public static <T> void merge(T source, T target) {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
modelMapper.map(source, target);
}
I have used spring boot, try to retrieve all the product from the database ( MySQL ) . But list size is zero. There is no error is shown to console.
This is my controller:
#RequestMapping(value = "/showListOfProduct", method=RequestMethod.GET)
public String showList(Model model) {
List<Products> allProduct = productService.listAllProducts();
System.out.println("sizeEEEEEEEEEEEEEE"+ allProduct.size());
model.addAttribute("allProduct", allProduct);
return "showlist";
}
This is repository:
#Repository
public interface ProductRepository extends JpaRepository<Products, Long> {
}
This is service:
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public List<Products> listAllProducts() {
return productRepository.findAll();
}
This is my Entity:
#Entity
#Table(name="products")
public class Products {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
#Column(name="productname")
private String productName;
#Column(name="numberofavailableinstock")
private long numberofavailableInStock;
#Column(name="productprice")
private String productPrice;
#Column(name="percentageofsell")
private double percentageOfSell;
// setter getter
This is my application.properties:
> spring.mvc.view.prefix: webapp/WEB-INF/jsp/ spring.mvc.view.suffix:
> .jsp server.port=7000 spring.datasource.url=
> jdbc:mysql://localhost:3306/myproduct spring.datasource.username=root
> spring.datasource.password=root
> spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.show-sql=true
My database is:
> Table: products Columns: id int(11) AI PK productname varchar(45)
> productprice varchar(45) numberofavailableinstock varchar(45)
> percentageofsell varchar
Usually when I run into this type of issue, its because my #Entity and the schema don't match up properly.
You should consider adding these two properties to your application.properties:
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
That will help you keep schema and entity matching.
i'm facing this issue while using Spring JPA and trying to retrieve a List of objects.
This is the class i'm trying to retrieve
#Entity
#Table(name="OBJECTSTERMIC")
public class TermicObject {
#Id
#Column(name="TERMICID")
private long termicId;
#MapsId
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name="OBJECTID",columnDefinition="INTEGER")
private Object object;
#Column(name="CONTECA_RIF")
private int contecaRif;
#Column(name="CONTECA_VAL")
private int contecaVal;
#Column(name="TYPE")
private String type;
//getters and setters
The Object class has the primary key on MySQL stored as an Integer, indeed this is Object
#Entity
public class Object {
#Column(name="OBJECTID")
#Id
#JsonProperty("OBJECTID")
private int objectId;
....
So, nowhere is set a Long...
Now, i simply call in a service class
#Override
public List<TermicObject> findAll() {
return repository.findAll();
}
and got this exception
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TypeMismatchException: Provided id of the wrong type for class it.besmart.db_eipo.persistence.model.Object. Expected: class java.lang.Integer, got class java.lang.Long; nested exception is java.lang.IllegalArgumentException: org.hibernate.TypeMismatchException: Provided id of the wrong type for class it.besmart.db_eipo.persistence.model.Object. Expected: class java.lang.Integer, got class java.lang.Long
Where is set that Object Id should be Long?
Have a look at definition of your repository. Does it have right generic type? do you have Integer as second parameter? IMHO this can be root cause. See proposed correct version:
#RepositoryRestResource
public interface TermicObjectRepository extends JpaRepository<TermicObject, Integer> {
public Optional<TermicObject> findById(Integer id);
public List<TermicObject> findAll()
}
As per #Lubo's answer, in my case I was having compatibility issues between String and Long types and as my model required a Long autogenerated id I had to change the repository from
public interface ProductRepository extends JpaRepository<Product, String> {
}
to
public interface ProductRepository extends JpaRepository<Product, Long> {
}
And my controller from
#RequestMapping(path = "/products/delete/{id}", method = RequestMethod.DELETE)
public void deleteProduct(#PathVariable(name = "id") String id) {
productRepository.deleteById(id);
}
to
#RequestMapping(path = "/products/delete/{id}", method = RequestMethod.DELETE)
public void deleteProduct(#PathVariable(name = "id") Long id) {
productRepository.deleteById(id);
}
You have to define your id as a Long datatype.
#Id
#Column(name="TERMICID")
private Long termicId;
also make a change in your repository interface:
public interface ProductRepository extends JpaRepository<Product, Long> {
}
Got this because
public class MyEntity {
#Id()
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private int id; // <-------- int
...
public long getId() { return id; } // <-------- long
}
Not completely sure, but I think this mapping
#Id
#Column(name="TERMICID")
private long termicId;
#MapsId
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name="OBJECTID",columnDefinition="INTEGER")
private Object object;
Makes the id of the Object match the value of termicId which is a long.
use
Long.valueOf(intValue)
to cast int to Long type because you define type Long to #Id
I create 3 model classes in playframework, and set one-one relationship and one-to many relationship in one of the class. The code snippet are as follows:
Person.java
///////////////////////
#Entity
#Table(name = "person")
public class Person extends Model{
#Id
private Long id;
private String lastName;
private String firstName;
private String userId;
private Address address;
private List<Task> tasks;
....
}
Task.java
//////////////////////////
#Entity
#Table(name = "task")
public class Task extends Model{
#Id
private Long id;
private String name;
private String descript;
private String details;
...........
}
Address.java
////////////////////
#Entity
#Table(name = "address")
public class Address extends Model{
#Id
private Long id;
private String street;
private String state;
.........
}
I create person object and set the attributes/one-one/one-many relationships.
I try to save the person object with both attributes and relationships to mysql db by calling person.save().However, it ends up saving only attributes userId/firstName/LastName. the address object and tasks list object are not saved in db.
My question is : is there any way to save the relationship objects in db long with person.save()? that is , after calling person.save(), address table and task table create new entires corresponding to them.
I end up setting foreign keys in person class to handle this relationship manually.
Thanks in advance!
You might want to have a look at a JPA tutorial in particular topics about #OneToMany and #OneToOne annotations. I'd recommend https://en.wikibooks.org/wiki/Java_Persistence/OneToMany and https://en.wikibooks.org/wiki/Java_Persistence/OneToOne.
I am working on a Spring MVC app in which there are two model classes: LocationModel and ContactModel. Below is the code:
#Entity
#Table(name="Contact")
public class ContactModel {
#Id
#Column(name="contactid")
#GeneratedValue
private int contactId;
#Column(name="contactname")
private String contactName;
#Column(name="contactemail")
private String email;
#Column(name="contactphone")
private String phone;
#ManyToOne
#JoinColumn(name="locationid")
private LocationModel locationModel;
}
#Entity
#Table(name="Location")
public class LocationModel {
#Id
#Column(name="locationid")
#GeneratedValue
private int locationId;
#Column(name="locationname")
private String locationName;
#Column(name="locationdesc")
private String locationDescription;
#Column(name="type")
private String locationType;
#Column(name="address")
private String address;
#Column(name="state")
private String state;
#Column(name="circle")
private int circle;
#Column(name="district")
private int district;
#Column(name="town")
private int town;
#Column(name="lattitude")
private String lattitude;
#Column(name="longitude")
private String longitude;
#Column(name="locationuid")
private String locationUID;
#Column(name="category")
private String category;
#Column(name="bedcount")
private int bedCount;
#OneToMany(mappedBy = "locationModel", fetch = FetchType.EAGER)
private List<ContactModel> contactList;
}
Primary key in location table is foreign key in contact table. I have 2 records in contact table, with location id 0.
I am using following code for getting contact list:
Session session = sessionFactory.getCurrentSession();
Query query = session
.createQuery("from ContactModel where contactName like :contactName");
return query.setParameter("contactName", contactName + "%").list();
But it shows exception:
Error performing load command : org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.bizmerlin.scm.model.LocationModel#0]
17:03:31,135 ERROR [stderr] (http--127.0.0.1-9090-2) org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.bizmerlin.scm.model.LocationModel#0]
17:03:31,139 ERROR [stderr] (http--127.0.0.1-9090-2) at org.hibernate.internal.SessionFactoryImpl$1$1.handleEntityNotFound(SessionFactoryImpl.java:247)
17:03:31,141 ERROR [stderr] (http--127.0.0.1-9090-2) at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:214)
17:03:31,143 ERROR [stderr] (http--127.0.0.1-9090-2) at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:264)
Perhaps it is due to that fact that location table has no record with location id 0. If so, how can I get contact list, even if their location is null?
Use optional attribute
#ManyToOne(optional=true)
#JoinColumn(name="locationid")
private LocationModel locationModel;
http://learningviacode.blogspot.in/2011/12/one-to-many-assocition-that-is-optional.html