I need help to resolve such problem. Application needs to support several DB (MySQL, Oracle). After migration to JBoss 7 entity id auto generation was broken.
Etity example:
#Entity
#Table(name="foo")
public class Foo {
private Integer id;
private String model;
#Id
#SequenceGenerator(name="foo_seq_gen", sequenceName="foo_0", initialValue=1, allocationSize=1)
#Column(name="id", updatable=false)
#GeneratedValue(generator = "foo_seq_gen")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name="model", length=64, updatable=false)
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
For Oracle it works fine. But when trying to perform create operation on MySQL following error occures:
15:34:56,290 ERROR [org.hibernate.util.JDBCExceptionReporter] (http-localhost-127.0.0.1-8080-1) Table 'scheme.foo_0' doesn't exist
Thus MySQL tries to access non-existent table as sequence instead of using native autogeneration mechanism.
Does anybody know the cure?
Using "table" generator strategy didn't help.
Environment:
MySQL 5.5.16;
JBoss AS 7.1.0.Beta1;
Hibernate 3.6.1.
Thanks.
I' not sure if you need the #SequenceGenerator for Oracle, but with JBoss AS 7.1.0.CR1b and MySQL I have no problems with ID auto generation and this annotations:
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private long id;
Related
On execution of my spring boot application with MySQL as data source, it fails with below error message
Table 'schema.users_seq' doesn't exist
I have an #Entity class Users with an AUTO_INC field Id
#Entity
#Table(appliesTo = "users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="uid")
private long id;
}
Below is my User controller class
#RestController
#RequestMapping("/cm/api/user")
public class UserController {
#Autowired
UsersRepository usersRepository;
#GetMapping("/{username}")
public void getUser(#PathVariable("username") String userName) {
}
#PostMapping("/add")
public void addNewUser(#RequestBody Users users) {
usersRepository.save(users);
}
}
There are some other articles on the same issue, but it all ended with the question if the class has AUTO_INC field.
Your app tries to generate a long ID for your Users entity by retrieving a value from the users_seq. You need to change the #GeneratedValue(strategy = GenerationType.AUTO) according to your DDL structure. As you didn't include that in your post, I can only assume how you mapped it, so I can only recommend that you read this article by Hibernate maintainer Vlad Mihalcea about why you should not use the AUTO JPA GenerationType with MySQL and Hibernate.
I'm working on a Spring application that uses Hibernate 4.3 to manage data stored in a MySql database.
I want to simply update the value of this object:
#Table(name = "CONTENT")
public class KcContent {
#Id
#GeneratedValue
#Column(name = "ID")
#DocumentId
private Long id;
#Column(name="PRIORITY")
private Long priority;
// getter and setter
}
This is the point where I update the object:
private EntityManager entityManager;
#Transactional
public String checkAndManageActionsNewsletter(NewsletterActionRequestBean requestBean) {
List<String> newsIds = requestBean.getNewsIds();
// update priority based on position in list
for(long priority = 0; priority < newsIds.size(); priority++) {
String newsId = newsIds.get((int) priority);
long contentId = Long.parseLong(newsId);
KcContent news = getServiceCatalog().getContentService().find(contentId);
news.setPriority(priority);
}
}
Where #Transactional is imported from org.springframework.transaction.annotation.Transactional.
This code results in no update on database. I also tried to add after setPriority():
this.entityManager.merge(news)
this.entityManager.persist(news)
but it doesn't work.
I checked the reference to the object in the entityManager after the setPriority() method, and the value it's updated.
In the database instead the value is still the old value (0):
In the end, I tried to change values on database for the priority, and the application read them correctly, so the problem seems to be only on update.
There is some mistakes in the configuration?
Note: unfortunately I can't use JpaRepository.
Update:
This is the implementation of the find() method in the ContentService class:
public EntityManager getEntityManager() {
return entityManager;
}
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
#Transactional(readOnly=true)
public KcContent find(Long id) {
if (id == null){
return null;
}
return getEntityManager().find(KcContent.class, id);
}
Currently, we are using MySQL as a database and we use
#Generated Value(strategy = GenerationType.IDENTITY)
It's working perfectly in certain situations we need to migrate our database to Oracle at that time it's not working properly. If anyone knows what's the actual difference is present behind this and how it's working?
Quoting Java Persistence/Identity and Sequencing:
Identity sequencing uses special IDENTITY columns in the database to allow the database to automatically assign an id to the object when its row is inserted. Identity columns are supported in many databases, such as MySQL, DB2, SQL Server, Sybase and Postgres. Oracle does not support IDENTITY columns but they can be simulated through using sequence objects and triggers.
so I prefer to use SEQUENCE instead
Sequence objects use special database objects to generate ids. Sequence objects are only supported in some databases, such as Oracle, DB2, and Postgres. Usually, a SEQUENCE object has a name, an INCREMENT, and other database object settings. Each time the .NEXTVAL is selected the sequence is incremented by the INCREMENT.
Example :
#Entity
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="EMP_SEQ")
#SequenceGenerator(name="EMP_SEQ", sequenceName="EMP_SEQ", allocationSize=100)
private long id;
...
}
How could it "work properly" (you don't define basic info like what you mean by that) with Oracle ? I don't see the relevance of AUTO to your question - that simply lets an implementation choose what it wants to use.
"IDENTITY" (as per JPA javadocs and spec - what you should be referring to) means autoincrement. There is no such concept in Oracle, yet there is in MySQL, SQLServer and a few others. I would expect any decent JPA implementation to flag an error when even trying such a thing.
Oracle would allow "SEQUENCE", or "TABLE" strategies to be used however
Im using JPA and Oracle 11g, the solution that worked for me is the following
package com.example.springsocial.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
#Entity
#Table(name = "rol", uniqueConstraints = {
#UniqueConstraint(columnNames = "name")
})
public class Rol {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="rol_sequence")
#SequenceGenerator(name="rol_sequence", sequenceName="rol_sequence", allocationSize=100)
private Long id;
#Column(nullable = false)
private String name;
private Date createdAt;
#Column(nullable = true)
private Date updatedAt;
#Column(nullable = true)
private Integer createdBy;
#Column(nullable = true)
private Integer updatedBy;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
public Integer getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(Integer updatedBy) {
this.updatedBy = updatedBy;
}
}
There are two problems that I do not understand.
First, the error message on the console. It does not give me the whole error message. Therefore I do not understand the issue at all :S The IDE is STS.
Second, why do I get this error, "JsonMapping failed to lazily initialize a..."
#Test
public void testUpdateCar() throws Exception {
Car car = carRepository.findById(new Long(1)).get();
car.setBrand("Mazda");
car.setModel("326");
String putJSON = objectMapper.writeValueAsString(car);
mockMVC.perform(MockMvcRequestBuilders.put(String.format("/api/cars/%d", car.getId())).contentType(MediaType.APPLICATION_JSON_UTF8).content(putJSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isCreated())
.andExpect(MockMvcResultMatchers.content().contentType("application/hal+json;charset=UTF-8"));
}
Car:
#Entity
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne
private User owner;
private String brand;
private String model;
private String color;
private String plate;
private String additionals;
Update 1:
The error itself:
com.fasterxml.jackson.databind.JsonMappingException: failed to lazily
initialize a collection of role:
me.eraytuncer.carpool.entity.User.carList, could not initialize proxy
- no Session (through reference chain: me.eraytuncer.carpool.entity.Car["owner"]->me.eraytuncer.carpool.entity.User["carList"])
Update 2:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String phone;
private String email;
#OneToMany(cascade = CascadeType.REMOVE, mappedBy = "owner")
private List<Car> carList;
Update 3:
#PutMapping("/cars/{id}")
ResponseEntity<?> replaceCar(#RequestBody Car newCar, #PathVariable Long id) {
if (repository.existsById(id)) {
newCar.setId(id);
Resource<Car> carResource = assembler.toResource(repository.save(newCar));
try {
return ResponseEntity
.created(new URI(carResource.getId().expand().getHref()))
.body(carResource);
} catch (URISyntaxException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
} else {
throw new CarNotFoundException(id);
}
}
Update 4:
Adding #JsonIgnore solved the issue somehow. Maybe it was a misleading issue caused by infinite recursion?
Looks like field
private List<Car> carList;
is resolved lazily (default fetch type in #OneToMany), which means it is populated from DB only when getter for this field is called. In your case it is called by Jackson serializer outside scope of the Hibernate session and property cannot be populated. Changing fetch type to EAGER in #OneToMany on carList property should help.
Also consider using DTO pattern, because returning entities from API is considered as bad practice.
You have mapped #OneToOne against #OneToMany. It should be #ManyToOne on the owning side:
#ManyToOne
#JoinColumn(name = "user_id") // if needed
private User owner;
I faced the same issue and it got resolved by using #Transactional on the method. #Transactional help to keep open the session so that lazy collection could be fetched.
I have an application which was running on H2 database and Hibernate is the ORM tool. Currently, I am changing this application to use mysql database instead of H2 database and while doing this I came to this issue when saving flagjp entity.
Here is the FlagJP entity that caused this issue.
#Entity
public class FlagJP extends BaseModelJP {
#Id
#GeneratedValue(generator = "IdOrGenerated")
#GenericGenerator(name = "IdOrGenerated", strategy = "com.jp.menu.api.model.JPSequenceGenerator")
private Long flagId;
private String flagKey;
#OneToMany(mappedBy="flag", cascade = CascadeType.ALL)
private List<FlagLangJP> flagLangs = new ArrayList<>();
#ManyToOne
private FlagCategoryJP flagCategory;
Here are the related entities for the FlagJP
Second entity
#Entity
public class FlagLangJP extends BaseModelJP {
#Id
#GeneratedValue(generator = "IdOrGenerated")
#GenericGenerator(name = "IdOrGenerated", strategy = "com.jp.menu.api.model.JPSequenceGenerator")
private Long id;
private String languageCode;
private String flagName;
private String flagDescription;
#ManyToOne
private FlagJP flag;
Third Entity
#Entity
public class FlagCategoryJP extends BaseModelJP {
#Id
#GeneratedValue(generator = "IdOrGenerated")
#GenericGenerator(name = "IdOrGenerated", strategy = "com.jp.menu.api.model.JPSequenceGenerator")
private Long flagCategoryId;
private String flagCategoryName;
#OneToMany(mappedBy = "flagCategory")
private List<FlagJP> flags;
While looking into this issue, I was able to figure out that this is cased by FlagJP table schema not having auto increment set in the database when hibernate generated the DDL.
here is the DDL of FlagJP
If I try to manually set the auto increment by executing a sql query, then mysql throw this error.
Operation failed: There was an error while applying the SQL script to the database.
ERROR 1833: Cannot change column 'flagId': used in a foreign key constraint 'FK_sk95esyf1n0gt1qqmlmdmq0uw' of table 'butterfly_emenu.flaglangbpa'
SQL Statement:
my question is , this problem does not happen when using H2 database. how to solve this issue using hibernate when the database is mysql.
Thanks in advance for any advice
Update:
Here is the code for sequence generator I am using
public class JPSequenceGenerator extends IdentityGenerator {
private static final Logger logger = LoggerFactory.getLogger(JPSequenceGenerator.class);
#Override
public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
Serializable id = session.getEntityPersister(null, object).getClassMetadata().getIdentifier(object, session);
if (id == null) {
id = super.generate(session, object);
}
return id;
}
}
Try below code with auto_increment field ID in mysql
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long flagId;
If you are not able to add auto_increment for flagId then remove the foreignKey FK_sk95esyf1n0gt1qqmlmdmq0uw then add auto_increment and add foreign key again