I added unique constraint annotation but still I can insert duplicate entry.
#Entity
#Table(uniqueConstraints = {#UniqueConstraint(columnNames = {"firstName", "LastName"})})
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String LastName;
//getter and setter and no-arg constructor
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Student student1 = new Student("alireza", "rayani");
Student student2 = new Student("alireza", "rayani");
session.save(student1);
session.save(student2);
session.getTransaction().commit();
Finally ,I found out the problem ,I changed dialect from
properties.put(Environment.DIALECT,"org.hibernate.dialect.MySQL5Dialect");
to
properties.put(Environment.DIALECT, "org.hibernate.dialect.MySQL57Dialect");
The schema for your database is generated by Hibernate? #UniqueConstraint is only used to generate the schema. If the database already exists, you should execute the alter table on it to add the constraint.
Related
I had a column useless_id in table foo. This column is foreign key into other table.
I have mapped it like this
#Entity
#Table(name = "foo")
public class Foo{
#Column(name = "useless_id")
private Integer uselessId;
//...
}
Everything worked perfect. But I decided to change the name of column useless_id into useful_id.
After that appear problems. When I try to save an Foo object: session.save(new Foo(...)) I get Unknown column F.useless_id in 'where clause'.
The query is printed in console insert into foo (..., useful_id, ...) value (...)
In list of columns I don't see useless_id.
Why I get Unknow column useless_id in 'where clause' ? Why use where when insert?
It is was changed everywhere. Even in Foo object
I get this error only when try to save.
UPDATE(Foo class is Order Class and useful_id is customer_id):
#Entity
#Table(name = "orders")
public class Order{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "status")
private Integer status;
#Column(name = "customer_id")
private Integer customerId;
#Column(name = "shipping_address")
private String shippingAddress;
//setters getters
}
#Entity
#Table(name = "customers")
public class Customer{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
//setters getters
}
This is how I try to insert new object
//...
session.beginTransaction();
Order order = new Order();
//set random values. customer_id get valid value, it exists in customers
session.save(order);
session.getTransaction().commit();
session.close();
For DESCRIBE orders; command I get:
Field----------------Type-----------Null---Key---Default---Extra
id-------------------int(11)--------NO-----PRI---NULL------auto_increment
status---------------int(50)--------NO-----------NULL------
customer_id----------int(50)--------NO-----MUL---NULL------
shipping_address-----varchar(191)---NO-----------NULL------
I found the problem.
It raised from MySQL. I found it by tried to insert with SQL command, direct to MySQL. Same error.
So I was looking very carefully in db and I found the problem is from triggers. In one of triggers still use old name of column.
Now make sense: Unknow column useless_id in 'where clause'. That where clause was in trigger which try to find useless_id, but it no longer exists.
CONCLUSION: After change name of column, check triggers.
In your java class you changes column name from useless_id to userful_id, but same think you didnt changes in your DB structure due to which you see this error.
I am trying to implement ManyToMany bidirectional mapping in Hibernate. But, when I test the application by persisting non-owning side object, Hibernate does not persist data in join table.
Here is my code:
College.java:
#Entity
#Table(name="college")
public class College {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="college_id")
private int id;
#Column(name="college_name")
private String name;
#ManyToMany(mappedBy="colleges",cascade=CascadeType.ALL)
private Set<Certification> certifications;
// getters and setters
}
Certification.java:
#Entity
#Table(name="certification")
public class Certification {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="certification_id")
private int id;
#Column(name="certification_name")
private String name;
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name="certification_college",joinColumns=#JoinColumn(name="certification_id"),inverseJoinColumns=#JoinColumn(name="college_id"))
private Set<College> colleges;
// getters and setters
}
MainApplication.java:
public class MainApplication{
public static void main(String[] args) {
Certification certification1 = new Certification();
certification1.setName("Java");
Certification certification2 = new Certification();
certification2.setName("C++");
Set<Certification> certifications = new HashSet<Certification>();
certifications.add(certification1);
certifications.add(certification2);
College college1 = new College();
college1.setName("ABC");
college1.setCertifications(certifications);
College college2 = new College();
college2.setName("XYZ");
college2.setCertifications(certifications);
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
session.save(college1);
session.save(college2);
transaction.commit();
sessionFactory.close();
}
}
Here's the SQL Output:
Hibernate: insert into college (college_name) values (?)
Hibernate: insert into certification (certification_name) values (?)
Hibernate: insert into certification (certification_name) values (?)
Hibernate: insert into college (college_name) values (?)
Thank you.
You're missing the #JoinTable annotation in your College.java class. You're persisting an entity that is not aware of the table that maps the relationship.
Add the following code after the #ManyToMany annotation of the "certifications" attribute.
#JoinTable(name="certification_college",joinColumns=#JoinColumn(name="college_id"),inverseJoinColumns=#JoinColumn(name="certification_id"))
Really confused by how one to many works in JPA, all the documents that I read, uses both one to many and many to one in their example, and I don't know if they are necessary or not, and it doesn't work when I tried it.
My question is, suppose I have two tables, and I want to populate the College object using findCollegeData() method, so that all the student in this college are in a list when I initialize the object.
Below is my approach, I am able to store all the students in the college list using storeCollegeData() method, but I am not able to retrieve the college object fully, the student list is always empty, even though the data is in the database, and it works if I try to search for student using college name directly.
public static EntityManager entityManager = something;
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public College {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int cId;
private String collegeName;
private int numOfStudent;
#OneToMany(mappedBy="collegeName", cascade=CascadeType.ALL, orphanRemoval=true)
private List<Student> studentList = new ArrayList<>();
}
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public Student {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int sId;
private String name;
private String collegeName;
private String city;
}
// college.getStudentList is always empty and I don't know why
public findCollegeData(String collegeName) {
College college = entityManager.find(College.class, collegeName);
}
// Student data in the studentList are inserted into student table
public storeCollegeData(College college) {
entityManager.persist(college);
}
// This method works
public findStudent(String collegeName) {
CriteriaBuilder cb = provider.get().getCriteriaBuilder();
CriteriaQuery<Student> query = cb.createQuery(Student.class);
Root<Student> student = query.from(Student.class);
query.where(
cb.and(
cb.equal(student.get("collegeName"), collegeName)
)
);
JobStatisticDB Student = provider.get().createQuery(query).getSingleResult();
}
Am i missing something??? Is join more appropriate than map here??? I dont know wat to do man
EDITED:
Got it to work by changing both of the collegeName as the primary key of table by adding #Id annotation, however though, how can I add an sId and cId to the table, so they can have duplicate college name???? Right now, I can't have duplicate college with the same name, and student that that goes to the same college!
Final Edited:
Changed database design to use foreign key see solution below
The accepted answer is incorrect: you define relationships between entities. The mappings should be as below for a bi-directional #OneToMany
College:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public College {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int cId;
private String collegeName;
private int numOfStudent;
#OneToMany(mappedBy="college", cascade=CascadeType.ALL, orphanRemoval=true)
private List<Student> studentList = new ArrayList<>();
}
Student:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public Student {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int sId;
private String name;
private String city;
//student table has a FK column college_id
#ManyToOne
#JoinColumn(name = "college_id")
private College college;
}
EntityManager find() takes the PK as an argument:
public findCollege(int collegeId) {
College college = entityManager.find(College.class, collegeId);
college.getStudents(); //will be populated
}
public findStudent(int studentId) {
Student student = entityManager.find(Student.class, studentId);
student.getCollege(); //will be populated
student.getCollege().getStudents(); //will be populated
}
If you want to find a college by name create a JPQL or Criteria query:
The field you reference in mappedBy must contain a value that equates to College's id field. Change it to collegeName instead of city, and it should work.
This question is similar to this one but the person asking never confirmed if it worked.
entityManager.persist(user) -> javax.persistence.EntityExistsException: User#b3089 is already persistent
Scenario
ProductCategory has a OneToMany relationship with Account which inversely has a ManyToOne relationship wuth ProductCategory. When ProductCategory is inserted, Accounts are not available. So ProductCategory is inserted without accounts. Later when accounts are available, I would like to insert accounts in the accounts table and also update ProductCategory with Accounts. The issue is with updating accounts in ProducCategory. When I use mgr.persist for productCategory, I get a error Entity already is Persistent!. When I do not use persist (as per suggestion the link, provider(datanucleus) will take care of writing it to the database at commit time), it does not update. The entities and methods are as follows:
#Entity
public class ProductCategory {
#Id
#Column(name = "CAT_ID", allowsNull="false")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key catId;
#Column(name = "CAT_SHORT_NAME", length=30)
private String catShortName;
//other fields
#OneToMany(mappedBy="productCategory",targetEntity=Account.class,
fetch=FetchType.EAGER, cascade=CascadeType.ALL)
private ArrayList<Account> accounts;
//getters & setters
#Entity
public class Account {
#Id
#Column(name = "ACCT_NBR_KEY", allowsNull="false")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key acctNbrKey;
#Column(name = "CAT_ID")
private Key acctCatId;
//other fields
#ManyToOne(optional=false, fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name="CAT_ID", insertable=false, updatable=false)
private ProductCategory productCategory;
//getters & setters
AccountEndpoint.java
public void insertAccountBulk() {
log.info("AccountEndpoint.insertAccountBulk....");
Account account = new Account();
ProductCategory pc = (new ProductCategoryEndpoint()).getProductCategoryByShortName("Savings");
account.setProductCategory(pc);
account.setAcctCatId(pc.getCatId());
//setting other fields
//updationg accounts in product category
getEntityManager().detach(pc);
if(pc.getAccounts() == null){
ArrayList<Account> accts = new ArrayList<Account>();
accts.add(account);
pc.setAccounts(accts);
}
else{
pc.getAccounts().add(account);
}
getEntityManager().merge(pc);
**//new ProductCategoryEndpoint().updateProductCategory(pc);**
ProductCategoryEndpoint.java
#ApiMethod(name = "updateProductCategory")
public ProductCategory updateProductCategory(ProductCategory productcategory) {
EntityManager mgr = getEntityManager();
try {
if (!containsProductCategory(productcategory)) {
throw new EntityNotFoundException("Object does not exist");
}
mgr.persist(productcategory);
} finally {
mgr.close();
}
return productcategory;
}
**If I uncomment new `ProductCategoryEndpoint().updateProductCategory(pc)` I get the error Entity already persistent.
If I keep it commented, the account is not updated in ProductCategory**
Judging by your other question you're using GAE/Datastore NOT RDBMS, and so are not using Hibernate - please update your question and remove that tag.
About the problem, if the entity is already persistent then you are trying to persist an object with a particular Key when an object with that Key already exists (i.e you passed a TRANSIENT object to persist. You should pass a DETACHED object to that method. The log would tell you what state objects are in
Try changing the #JoinColumn annotation to allow inserts and updates of the ProductCategory. I think it is preventing the Categories from being associated with the Account.
#ManyToOne(optional=false, fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name="CAT_ID")
private ProductCategory productCategory;
I have two persistence entity: User and UserDetail. They have one-to-one relationship. I use hibernate annotations. But I am getting in my database several objects of user information for one same user. Apparently my knowledge of Hibernate annotations are not so good to solve this problem.
User class:
#Entity
#Table(name = "USER")
public class User {
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "PASSWORD")
private String password;
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private UserDetail userDetail;
// setters and getters
}
UserDetail class:
#Entity
#Table(name = "USER_DETAIL")
public class UserDetail {
#OneToOne
#JoinColumn(name = "USER_ID")
private User user;
// other fields
}
I use this in my code as follows:
UserDetail userDetail = new UserDetail();
userDetail.setInfo(info);
userDetail.setUser(seventhUser);
hibernateTemplate.saveOrUpdate(userDetail);
And everything works properly. Here's what my table USER_DETAIL:
But when I try to change user information, I get an incorrect behavior. I get following table after I again set user information:
UserDetail newUserDetail = new UserDetail();
newUserDetail.setInfo(newInfo);
newUserDetail.setUser(seventhUser);
hibernateTemplate.saveOrUpdate(newUserDetail);
Why the same two objects of information correspond to one user?? I have One-To-One relationship. How can I avoid this? What am I doing wrong?
If you want to modify an existing UserDetail, then you must set its ID, or get it from the session and modify it. Else, Hibernate thinks it's a new one that must be saved, since it doesn't have any ID.
UserDetail existingUserDetail = session.get(UserDetail.class, theUserDetailId);
existingUserDetail.setInfo(newInfo);
To make sure you don't save two UserDetail instances for the same user, you should add a unique constraint on the USER_ID column of the UserDetail database table.