I am using objectify. Say, I have a User kind with name and email properties. When implementing signup, I want to check if a user with same name or same email is already registered. Because signup can be called from many sources a race condition might occur.
To prevent race condition everything must be wrapped inside a transaction somehow. How can I eliminate the race condition?
The GAE documents explain how to create an entity if it doesn't exist but they assume the id is known. Since, I need to check two properties I can't specify an id.
Inspired by #konqi's answer I have came up with a similar solution.
The idea is to create User_Name and User_Email entities that will keep the name and emails of all the users created so far. There will be no parent relationship. For convenience we are going to keep name and email properties on user too; we are trading storage for less read/write.
#Entity
public class User {
#Id public Long id;
#Index public String name;
#Index public String email;
// other properties...
}
#Entity
public class User_Name {
private User_Name() {
}
public User_Name(String name) {
this.name = name;
}
#Id public String name;
}
#Entity
public class User_Email {
private User_Email() {
}
public User_Email(String email) {
this.email = email;
}
#Id public String email;
}
Now create user within a transaction by checking unique fields:
User user = ofy().transact(new Work<User>() {
#Override
public User run()
{
User_Name name = ofy().load().key(Key.create(User_Name.class, data.username)).now();
if (name != null)
return null;
User_Email email = ofy().load().key(Key.create(User_Email.class, data.email)).now();
if (email != null)
return null;
name = new User_Name(data.username);
email = new User_Email(data.email);
ofy().save().entity(name).now();
ofy().save().entity(email).now();
// only if email and name is unique create the user
User user = new User();
user.name = data.username;
user.email = data.email;
// fill other properties...
ofy().save().entity(user).now();
return user;
}
});
This will guarantee uniqueness of those properties (at least my tests empirically proved it :)). And by not using Ref<?>s we are keeping the data compact which will result in less queries.
If there was only one unique property it is better to make it #Id of the main entity.
It is also possible to set the #Id of the user as email or name, and decrease the number of new kinds by one. But I think creating a new entity kind for each unique property makes the intent (and code) more clear.
I can think of two possible solutions:
Using entity design:
Lets say you have a User #Entity which will use the email address as #Id. Then you create a Login #Entity which has the Name as #Id and a Ref<User> to the User. Now both can be queried for with key queries which can be used in transactions. This way it's impossible to have duplicates.
#Entity
public class User {
#Id
private String email;
}
#Entity
public class Login {
#Id
private String name;
private Ref<User> user;
}
Using indexed composite property:
You can define an indexed composite property that contains both values like this (Note: This just shows what i mean by indexed composite property, do not implement it like that):
#Entity
public class User {
#Id
private Long id;
private String email;
private String name;
#Index
private String composite;
#OnSave
private onSave(){
composite = email + name;
}
}
However, as stickfigure pointed out there is no guarantee for uniqueness if you use an indexed property in a transaction (as a matter of fact you can't query by indexed property in a transaction at all).
That is because in a transaction you can only query by key or ancestor. So what you need to to is outsource your composite key into a separate #Entity that uses the composite key as #Id.
#Entity
public class UserUX {
// for email OR name: email + name (concatenation of two values)
// for email AND name: email OR name
// (you would create two entities for each user, one with name and one with the email)
#Id
private String composite;
private Ref<User> user;
}
This entity is usable in a key query and therefor in a transaction.
Edit:
If, as commented on this answer you wish to 'restricts users with same email and name' you can use the UserUX entity as well. You would create one with the email and one with the name. I added code comments above.
This is from the python sdk but the concepts should translate to java
http://webapp-improved.appspot.com/_modules/webapp2_extras/appengine/auth/models.html#Unique
"""A model to store unique values.
The only purpose of this model is to "reserve" values that must be unique
within a given scope, as a workaround because datastore doesn't support
the concept of uniqueness for entity properties.
For example, suppose we have a model `User` with three properties that
must be unique across a given group: `username`, `auth_id` and `email`::
class User(model.Model):
username = model.StringProperty(required=True)
auth_id = model.StringProperty(required=True)
email = model.StringProperty(required=True)
To ensure property uniqueness when creating a new `User`, we first create
`Unique` records for those properties, and if everything goes well we can
save the new `User` record::
#classmethod
def create_user(cls, username, auth_id, email):
# Assemble the unique values for a given class and attribute scope.
uniques = [
'User.username.%s' % username,
'User.auth_id.%s' % auth_id,
'User.email.%s' % email,
]
# Create the unique username, auth_id and email.
success, existing = Unique.create_multi(uniques)
if success:
# The unique values were created, so we can save the user.
user = User(username=username, auth_id=auth_id, email=email)
user.put()
return user
else:
# At least one of the values is not unique.
# Make a list of the property names that failed.
props = [name.split('.', 2)[1] for name in uniques]
raise ValueError('Properties %r are not unique.' % props)
"""
I am getting a ConstraintViolationException when I try to saveOrUpdate using hibernate. When I insert a brand new object for a user, the save works perfectly but when I try to update it fails.
In the database table I have a unique not null primary key and a unique not null foreign key named userid
My pojo declaration is as follows;
#Id #GeneratedValue
#Column(name = "id")
private int id;
#Column(name="userid")
private int userid;
#Column(name = "homephonenumber")
protected String homeContactNumber;
#Column(name = "mobilephonenumber")
protected String mobileContactNumber;
#Column(name = "photo")
private byte[] optionalImage;
#Column(name = "address")
private String address;
My insert statement looks as follows;
public boolean addCardForUser(String userid, Card card) {
if(StringUtilities.stringEmptyOrNull(userid)){
throw new IllegalArgumentException("Cannot add card for null or empty user id");
}
if(card == null){
throw new IllegalArgumentException("Cannot null card to the database for user " + userid);
}
SessionFactory sf = null;
Session session = null;
try{
sf = HibernateUtil.getSessionFactory();
session = sf.openSession();
session.beginTransaction();
session.saveOrUpdate(card);
session.getTransaction().commit();
return true;
}catch(Exception e){
logger.error("Unable to add Card to the database for user " + userid );
}finally{
DatabaseUtilities.closeSessionFactory(sf);
DatabaseUtilities.closeSession(session);
}
return false;
}
The exception I get says
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Duplicate entry '16' for key 'userid_UNIQUE'
And the database looks like this
What am I doing wrong, should the database entry not be updated?
For update, you should load the Card instance first, after some fields updated, then, invoke addCardForUser to update it, if the Card instance is not loaded via hibernate, hibernate will recogize it as a new record, if this card has the the userId with other card records in database, the unique constrain is violated!
You should not put a unique constraint on your foreign key. The foreign key models a one-to-many relation ship. While your parent-objects may only have one user, the same user may be related to many different parent objects. Thus, there will not necessarily be only one row in your parent object table for one userId.
I am finding that when the parent table in a one-to-many relationship is updated, the foreign keys of dependent data on the child table are being set to null leaving orphaned records on the child table.
I have two Java classes annotated with Hibernate tags. The parent table is:
#Entity
#Table(name = "PERSON")
public class Person implements Serializable {
// Attributes.
#Id
#Column(name="PERSON_ID", unique=true, nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer personId;
#Column(name="NAME", nullable=false, length=50)
private String name;
#Column(name="ADDRESS", nullable=false, length=100)
private String address;
#Column(name="TELEPHONE", nullable=false, length=10)
private String telephone;
#Column(name="EMAIL", nullable=false, length=50)
private String email;
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name="PERSON_ID")
private List<Book> books;
And the child table is:
Entity
#Table(name = "BOOK")
public class Book implements Serializable {
// Attributes.
#Id
#Column(name="BOOK_ID", unique=true, nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer bookId;
#Column(name="AUTHOR", nullable=false, length=50)
private String author;
#Column(name="TITLE", nullable=false, length=50)
private String title;
#Column(name="DESCRIPTION", nullable=false, length=500)
private String description;
#Column(name="ONLOAN", nullable=false, length=5)
private String onLoan;
// #ManyToOne
// private Person person;
But when an update is issued on a Person, any Books records related to the parent are set to null.
The Book table is:
CREATE TABLE BOOK (
BOOK_ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
AUTHOR VARCHAR(50) NOT NULL,
TITLE VARCHAR(100) NOT NULL,
DESCRIPTION VARCHAR(500) NOT NULL,
ONLOAN VARCHAR(5) NOT NULL,
PERSON_ID INTEGER,
CONSTRAINT PRIMARY_KEY_BOOK PRIMARY KEY(BOOK_ID),
CONSTRAINT FOREIGN_KEY_BOOK FOREIGN KEY(PERSON_ID) REFERENCES PERSON(PERSON_ID))
And the update method in the Person controller is:
#RequestMapping(value = "/profile", method = RequestMethod.POST)
public String postProfile(#ModelAttribute("person") Person person,
BindingResult bindingResult,
Model model) {
logger.info(PersonController.class.getName() + ".postProfile() method called.");
personValidator.validate(person, bindingResult);
if (bindingResult.hasErrors()) {
return "view/profile";
}
else {
personService.update(person);
model.addAttribute("person", person);
return "view/options";
}
}
And the actual DAO level method is:
#Override
public void update(Person person) {
logger.info(PersonDAOImpl.class.getName() + ".update() method called.");
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
try {
transaction.begin();
session.update(person);
transaction.commit();
}
catch(RuntimeException e) {
Utils.printStackTrace(e);
transaction.rollback();
throw e;
}
finally {
session.close();
}
}
So I'm assuming that update is the cause of the issue but why?
I have tried merge, persist and saveOrUpdate methods as alternatives but to no avail.
Concerning the fact that my Book table has no annotation for #ManyToOne, disabling this tag was the only way in which I could get LAZY fetching to work.
This case also seems very similar to Hibernate one to many:"many" side record's foreign key is updated to null automatically and Hibernate Many to one updating foreign key to null, but if I adopt the changes specified to classes in these questions to my own tables, my application refuses to even compile seemingly because of problems with the use of mappedBy in the Person table.
Any advice is welcome.
Controller method changed to:
// Validates and updates changes made by a Person on profile.jap
#RequestMapping(value = "/profile", method = RequestMethod.POST)
public String postProfile(#ModelAttribute("person") Person person,
BindingResult bindingResult,
Model model) {
logger.info(PersonController.class.getName() + ".postProfile() method called.");
// Validate Person.
personValidator.validate(person, bindingResult);
if (bindingResult.hasErrors()) {
return "view/profile";
}
else {
// Get current Person.
Person currPerson = personService.get(person.getPersonId());
// Set Books to updated Person.
person.setBooks(currPerson.getBooks());
personService.update(person);
model.addAttribute("person", person);
return "view/options";
}
}
And it works.
I assume that the postProfile() method receives a Person instance which only contains the ID, name, address etc. of the person, as posted by a web form, but that its list of books is null or empty.
And you're telling Hibernate to save that person. So you're effectively telling Hibernate that this person, identified by the given ID has a new name, a new address, a new email, ... and a new list of books which happens to be empty, and that this should be saved into the database.
So Hibernate does what you're telling it to do: it saves the new state of the person. And since the new person doesn't have any book, all the books it previously owned become owned by nobody.
You'll have to get the actual, persistent Person entity from the database, and copy the fields that should actually be modified from the new person to the persistent one.
Or you'll have to pre-load the persistent person from the database and make Spring populate this persistent person instead of creating a new instance per scratch. See http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/htmlsingle/#mvc-ann-modelattrib-methods.
You may also try to remove the #JoinColumn from the #OneToMany, and use mappedBy, instead.
See: Hibernate Many to one updating foreign key to null
I am having some problems with JPA. I am new at this topic so my question maybe is really stupid, but i hope some of you could point me to the right direction.
I have Project and User entity. Every user can have as many projects assign to him as it can.
I created the relationship bidirectional
User OneToMany -> Project,
Project ManyToOne -> User
My problem is that if i want to delete a user i want all the projects to be deleted as well, but i receive an error at that point:
Internal Exception: java.sql.SQLIntegrityConstraintViolationException:
DELETE on table 'USER_DATA' caused a violation of
foreign key constraint 'PROJECT_USERNAME' for key (Test Use1312r1).
The statement has been rolled back.
Error Code: -1
Call: DELETE FROM USER_DATA WHERE (USERNAME = ?)
bind => [1 parameter bound]
My User entity looks like this:
#Entity
#Table(name="USER_DATA", uniqueConstraints = #UniqueConstraint(columnNames = {"USERNAME", "link"}))
public class User implements Serializable {
#Column(name="USERNAME")
#Id
#NotNull
private String name;
#Column(name="USERROLE")
#Enumerated(EnumType.STRING)
private UserRole role;
private String password;
private String link;
// Should be unique
private String session;
#OneToMany(mappedBy="user", cascade=CascadeType.ALL)
private Collection<Project> projects;
My Project Entity like this:
#Entity
#Table(name="PROJECT")
#XmlRootElement
public class Project implements Serializable {
#Id
private int id;
private String name;
private String description;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="START_DATE")
private Date beginDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="END_DATE")
private Date endDate;
#ManyToOne
#JoinColumn(name="USERNAME", nullable=false,updatable= true)
private User user;
And my BL:
public User getUser(String userName) throws NoDataFoundException {
EntityManager em = DbConnection.getInstance().getNewEntity();
try {
User user = em.find(User.class, userName);
if (user == null) {
throw new NoDataFoundException("User is not found in the DB");
}
return user;
} finally {
em.close();
}
}
public void deleteUser(String userName) throws ModelManipulationException {
EntityManager em = DbConnection.getInstance().getNewEntity();
try {
User userToBeDeleted = getUser(userName);
em.getTransaction().begin();
userToBeDeleted = em.merge(userToBeDeleted);
em.remove(userToBeDeleted);
em.getTransaction().commit();
} catch (Exception e) {
throw new ModelManipulationException(
"Error in deleting user data for username" + userName
+ "with exception " +e.getMessage(),e);
}
finally{
em.close();
}
}
Thanks in advance guys.
after the merge call, are there any Projects in userToBeDeleted.projects? I suspect there are none, which prevents any from being deleted. Cascade remove can only work if you populate both sides of bidirectional relationships, so check that when you associate a user to a project, you also add the project to the user's project collection.
I'm facing what I think is a simple problem with Hibernate, but can't solve it (Hibernate forums being unreachable certainly doesn't help).
I have a simple class I'd like to persist, but keep getting:
SEVERE: Field 'id' doesn't have a default value
Exception in thread "main" org.hibernate.exception.GenericJDBCException: could not insert: [hibtest.model.Mensagem]
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
[ a bunch more ]
Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
[ a bunch more ]
The relevant code for the persisted class is:
package hibtest.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Mensagem {
protected Long id;
protected Mensagem() { }
#Id
#GeneratedValue
public Long getId() {
return id;
}
public Mensagem setId(Long id) {
this.id = id;
return this;
}
}
And the actual running code is just plain:
SessionFactory factory = new AnnotationConfiguration()
.configure()
.buildSessionFactory();
{
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
Mensagem msg = new Mensagem("YARR!");
session.save(msg);
tx.commit();
session.close();
}
I tried some "strategies" within the GeneratedValue annotation but it just doesn't seem to work. Initializing id doesn't help either! (eg Long id = 20L).
Could anyone shed some light?
EDIT 2: confirmed: messing with#GeneratedValue(strategy = GenerationType.XXX) doesn't solve it
SOLVED: recreating the database solved the problem
Sometimes changes made to the model or to the ORM may not reflect accurately on the database even after an execution of SchemaUpdate.
If the error actually seems to lack a sensible explanation, try recreating the database (or at least creating a new one) and scaffolding it with SchemaExport.
If you want MySQL to automatically produce primary keys then you have to tell it when creating the table. You don't have to do this in Oracle.
On the Primary Key you have to include AUTO_INCREMENT. See the example below.
CREATE TABLE `supplier`
(
`ID` int(11) NOT NULL **AUTO_INCREMENT**,
`FIRSTNAME` varchar(60) NOT NULL,
`SECONDNAME` varchar(100) NOT NULL,
`PROPERTYNUM` varchar(50) DEFAULT NULL,
`STREETNAME` varchar(50) DEFAULT NULL,
`CITY` varchar(50) DEFAULT NULL,
`COUNTY` varchar(50) DEFAULT NULL,
`COUNTRY` varchar(50) DEFAULT NULL,
`POSTCODE` varchar(50) DEFAULT NULL,
`HomePHONENUM` bigint(20) DEFAULT NULL,
`WorkPHONENUM` bigint(20) DEFAULT NULL,
`MobilePHONENUM` bigint(20) DEFAULT NULL,
`EMAIL` varchar(100) DEFAULT NULL,
PRIMARY KEY (`ID`)
)
ENGINE=InnoDB DEFAULT CHARSET=latin1;
Here's the Entity
package com.keyes.jpa;
import java.io.Serializable;
import javax.persistence.*;
import java.math.BigInteger;
/**
* The persistent class for the parkingsupplier database table.
*
*/
#Entity
#Table(name = "supplier")
public class supplier implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
**#GeneratedValue(strategy = GenerationType.IDENTITY)**
#Column(name = "ID")
private long id;
#Column(name = "CITY")
private String city;
#Column(name = "COUNTRY")
private String country;
#Column(name = "COUNTY")
private String county;
#Column(name = "EMAIL")
private String email;
#Column(name = "FIRSTNAME")
private String firstname;
#Column(name = "HomePHONENUM")
private BigInteger homePHONENUM;
#Column(name = "MobilePHONENUM")
private BigInteger mobilePHONENUM;
#Column(name = "POSTCODE")
private String postcode;
#Column(name = "PROPERTYNUM")
private String propertynum;
#Column(name = "SECONDNAME")
private String secondname;
#Column(name = "STREETNAME")
private String streetname;
#Column(name = "WorkPHONENUM")
private BigInteger workPHONENUM;
public supplier()
{
}
public long getId()
{
return this.id;
}
public void setId(long id)
{
this.id = id;
}
public String getCity()
{
return this.city;
}
public void setCity(String city)
{
this.city = city;
}
public String getCountry()
{
return this.country;
}
public void setCountry(String country)
{
this.country = country;
}
public String getCounty()
{
return this.county;
}
public void setCounty(String county)
{
this.county = county;
}
public String getEmail()
{
return this.email;
}
public void setEmail(String email)
{
this.email = email;
}
public String getFirstname()
{
return this.firstname;
}
public void setFirstname(String firstname)
{
this.firstname = firstname;
}
public BigInteger getHomePHONENUM()
{
return this.homePHONENUM;
}
public void setHomePHONENUM(BigInteger homePHONENUM)
{
this.homePHONENUM = homePHONENUM;
}
public BigInteger getMobilePHONENUM()
{
return this.mobilePHONENUM;
}
public void setMobilePHONENUM(BigInteger mobilePHONENUM)
{
this.mobilePHONENUM = mobilePHONENUM;
}
public String getPostcode()
{
return this.postcode;
}
public void setPostcode(String postcode)
{
this.postcode = postcode;
}
public String getPropertynum()
{
return this.propertynum;
}
public void setPropertynum(String propertynum)
{
this.propertynum = propertynum;
}
public String getSecondname()
{
return this.secondname;
}
public void setSecondname(String secondname)
{
this.secondname = secondname;
}
public String getStreetname()
{
return this.streetname;
}
public void setStreetname(String streetname)
{
this.streetname = streetname;
}
public BigInteger getWorkPHONENUM()
{
return this.workPHONENUM;
}
public void setWorkPHONENUM(BigInteger workPHONENUM)
{
this.workPHONENUM = workPHONENUM;
}
}
Take a look at GeneratedValue's strategy. It typically looks something like:
#GeneratedValue(strategy=GenerationType.IDENTITY)
you must be using update in your hbm2ddl property. make the changes and update it to Create so that it can create the table.
<property name="hbm2ddl.auto">create</property>
It worked for me.
Dropping the table from the database manually and then re-running the application worked for me. In my case table was not created properly(with constraints) I guess.
I had this issue. My mistake was i had set the insertable and updatable fileds as false and was trying to set the field in the request. This field is set as NON NULL in DB.
#ManyToOne
#JoinColumn(name="roles_id", referencedColumnName = "id", insertable = false, updatable = false, nullable=false)
#JsonBackReference
private Role role;
Later I changed it to - insertable = true, updatable = true
#ManyToOne
#JoinColumn(name="roles_id", referencedColumnName = "id", insertable = true, updatable = true, nullable=false)
#JsonBackReference
//#JsonIgnore
private Role role;
It worked perfectly later.
I came here because of the error message, turns out I had two tables with the same name.
I had the same problem. I found the tutorial Hibernate One-To-One Mapping Example using Foreign key Annotation and followed it step by step like below:
Create database table with this script:
create table ADDRESS (
id INT(11) NOT NULL AUTO_INCREMENT,
street VARCHAR(250) NOT NULL,
city VARCHAR(100) NOT NULL,
country VARCHAR(100) NOT NULL,
PRIMARY KEY (id)
);
create table STUDENT (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
entering_date DATE NOT NULL,
nationality TEXT NOT NULL,
code VARCHAR(30) NOT NULL,
address_id INT(11) NOT NULL,
PRIMARY KEY (id),
CONSTRAINT student_address FOREIGN KEY (address_id) REFERENCES ADDRESS (id)
);
Here is the entities with the above tables
#Entity
#Table(name = "STUDENT")
public class Student implements Serializable {
private static final long serialVersionUID = 6832006422622219737L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
}
#Entity
#Table(name = "ADDRESS")
public class Address {
#Id #GeneratedValue
#Column(name = "ID")
private long id;
}
The problem was resolved.
Notice: The primary key must be set to AUTO_INCREMENT
Another suggestion is to check that you use a valid type for the auto-generated field. Remember that it doesn't work with String, but it works with Long:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long id;
#Constraints.Required
public String contents;
The above syntax worked for generating tables in MySQL using Hibernate as a JPA 2.0 provider.
Just add not-null constraint
I had the same problem. I just added not-null constraint in xml mapping. It worked
<set name="phone" cascade="all" lazy="false" >
<key column="id" not-null="true" />
<one-to-many class="com.practice.phone"/>
</set>
Maybe that is the problem with the table schema. drop the table and rerun the application.
In addition to what is mentioned above, do not forget while creating sql table to make the AUTO INCREMENT as in this example
CREATE TABLE MY_SQL_TABLE (
USER_ID INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
FNAME VARCHAR(50) NOT NULL,
LNAME VARCHAR(20) NOT NULL,
EMAIL VARCHAR(50) NOT NULL
);
When your field is not nullable it requires a default value to be specified on table creation. Recreate a table with AUTO_INCREMENT properly initialized so DB will not require default value since it will generate it by itself and never put NULL there.
CREATE TABLE Persons (
Personid int NOT NULL AUTO_INCREMENT,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int,
PRIMARY KEY (Personid)
);
https://www.w3schools.com/sql/sql_autoincrement.asp
I solved it changuing #GeneratedValue(strategy = GenerationType.IDENTITY) by #GeneratedValue(strategy = GenerationType.AUTO)
By the way i didn't need to put it to create, just:
spring.jpa.hibernate.ddl-auto: update
Please check whether the Default value for the column id in particular table.if not make it as default
I had the same problem. I was using a join table and all I had with a row id field and two foreign keys. I don't know the exact caused but I did the following
Upgraded MySQL to community 5.5.13
Rename the class and table
Make sure I had hashcode and equals methods
#Entity
#Table(name = "USERGROUP")
public class UserGroupBean implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "USERGROUP_ID")
private Long usergroup_id;
#Column(name = "USER_ID")
private Long user_id;
#Column(name = "GROUP_ID")
private Long group_id;
The same exception was thrown if a DB table had an old unremoved column.
For example:
attribute_id NOT NULL BIGINT(20), and attributeId NOT NULL BIGINT(20),
After removing the not used attribute, in my case contractId, the problem was resolved.
This happened to me with a #ManyToMany relationship. I had annotated one of the fields in the relationship with #JoinTable, I removed that and used the mappedBy attribute on #ManyToMany instead.
I tried the code and in my case the code below solve the issue. I had not settled the schema properly
#Entity
#Table(name="table"
,catalog="databasename"
)
Please try to add ,catalog="databasename" the same as I did.
,catalog="databasename"
In my case,
I altered that offending tables and the field "id" in question I made it AUTO_INCREMENT, I still need to figure out why on deployment time it was not making it "AUTO_INCREMENT" so that I have to do it by myself!
What about this:
<set name="fieldName" cascade="all">
<key column="id" not-null="true" />
<one-to-many class="com.yourClass"/>
</set>
I hope it helps you.
Try to change Long object type to long primitive type (if using primitives is ok for you).
I had the same problem and changing type helped me.
I had this issue, by mistake I had placed #Transient annotation above that particular attribute. In my case this error make sense.
"Field 'id' doesn't have a default value" because you didn't declare GenerationType.IDENTITY in GeneratedValue Annotation.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
This issue is because sometimes you need to again update/create the database or sometimes if you have added the field in db table but not not entity class then it can not insert any null value or zero so this error came.
So check both side.Db and Entity class.
i have got such error in GCP cloud sql when model field didn't match correct table field in db.
Example:
when in model field is fieldName
table in db should have field field_name
Fixing table field name helped me.
I solved similar problem, when I altered the database column type , and did not add auto_increment. After adding back auto_increment in the alter table command (as in my original table creation) it worked
In my case I have not added the below property in my application.properties file:
spring.jpa.database-platform = org.hibernate.dialect.MySQL5InnoDBDialect
And added the following annotation to my entity class's Id column:
#GeneratedValue(strategy = GenerationType.IDENTITY)
And after adding this I have also drop my table manually from datatbase and run my project again that creates a new table with all default constraints for the table.
To delete just delete your schema is a really bad suggestion. There is a problem and it's best to find and fix it.
In my case I was using Envers this creates an Audit table for when entries are updated. But this audit table does not get updated itself it seems when the schema updates (At least not ID and it's relationships)
I just eddited the audit tables offending property and done. Everything back to normal.
To find what the issue is turn the following properties on in application.properties file
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
This will show you what SQL it is trying to executing and hopefully it will provide clarity on real issue.
Add a method hashCode() to your Entity Bean Class and retry it