I have a Spring MVC application that handle Users and Structures that can hosts one or more User.
I'm using Hibernate for the persistence and I'm having some issues with the One-To-Many relation between User and Structure.
This is my User model:
#Entity
#Table(name="USERS")
public class User extends DatabaseEntity {
#Id #GeneratedValue
private Long id = 0L;
#Column
#NotEmpty
private String firstName;
#Column
private String lastName;
#Column
private Date birthDate;
#Column
private String nation;
#Column
private String town;
#Column
private String idNumber;
#Column(unique = true)
private String email;
#Column String resetPasswordToken = "";
#Column
private String password;
#Column
private String avatarUrl;
#Column #Enumerated(EnumType.STRING)
private Role role;
#ManyToOne
#JoinColumn(name = "STRUCTURE_ID")
#Cascade({CascadeType.DETACH})
private Structure structure;
public enum Role {
ADMINISTRATOR,
SPECIALIST,
PATIENT,
DOCTOR,
CARE_GIVER
}
public User() {
birthDate = new Date();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public Set<Group> getGroups() {
return null;
}
public void setGroups(Set<Group> groups) {
}
public Set<Group> getCreatedGroups() {
return null;
}
public void setCreatedGroups(Set<Group> createdGroups) {
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Set<HangoutUser> getHangoutUsers() {
return null;
}
public void setHangoutUsers(Set<HangoutUser> hangoutUsers) {
}
public String getResetPasswordToken() {
return resetPasswordToken;
}
public void setResetPasswordToken(String resetPasswordToken) {
this.resetPasswordToken = resetPasswordToken;
}
public Group getStructure() {
return structure;
}
public void setStructure(Structure structure) {
this.structure = structure;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
if (!email.equals(user.email)) return false;
if (!id.equals(user.id)) return false;
return true;
}
#Override
public int hashCode() {
Long res = id;
if(id == null)
res = 0L;
int result = res.hashCode();
result = 31 * result + email.hashCode();
return result;
}
}
And this is my Structure model:
#Entity
#Table(name = "STRUCTURES")
public class Structure extends DatabaseEntity {
#Id #GeneratedValue
Long id = 0L;
#Column
String name;
#Column
String address;
#Column
String city;
#Column
String state;
#OneToMany(mappedBy = "structure", fetch = FetchType.EAGER)
#Cascade({CascadeType.DELETE})
Set<User> users = new HashSet<User>();
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 String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
public String getCity()
{
return city;
}
public void setCity(String city)
{
this.city = city;
}
public String getState()
{
return state;
}
public void setState(String state)
{
this.state = state;
}
public Set<User> getUsers()
{
return this.users;
}
public void setUsers(Set<User> users)
{
this.users = users;
}
}
My issue is that when I try to find all the Users with the value STRUCTURE_ID evaluated, I get an Hibernate Exception, like this:
org.springframework.orm.hibernate3.HibernateSystemException: Found two representations of same collection: it.amtservices.livinglab.model.Group.users; nested exception is org.hibernate.HibernateException: Found two representations of same collection: it.amtservices.livinglab.model.Structure.users
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:690) ...
What should I do to solve this problem? I have already tried many ways but nothing solved.
I paste the abstract repository implementation for the UsersRepository and StructureRepository:
#Transactional
public abstract class AbstractRepository<Model extends DatabaseEntity>
{
Logger logger = Logger.getLogger(this.getClass().getSimpleName());
#PersistenceContext
EntityManager em;
protected Class<Model> ModelClass;
protected List<Model> findBy(String parameterName, Object parameterValue)
{
Query q = em.createQuery("select t from " + ModelClass.getSimpleName() + " t where t." + parameterName + " = :" + parameterName);
q.setParameter(parameterName, parameterValue);
List<Model> results = null;
try
{
results = q.getResultList();
}
catch (Exception e)
{
return null;
}
return results;
}
protected List<Model> findBy(Map<String, Object> parameters)
{
String whereClause = "";
for (String key : parameters.keySet())
{
if (!whereClause.equals("")) whereClause += " and ";
whereClause += "t." + key + " = :" + key;
}
Query q = null;
try
{
q = em.createQuery("select t from " + ModelClass.getSimpleName() + " t where " + whereClause);
}
catch (Exception e)
{
e.printStackTrace();
}
for (String key : parameters.keySet())
{
q.setParameter(key, parameters.get(key));
}
List<Model> results = null;
try
{
results = q.getResultList();
}
catch (Exception e)
{
return null;
}
return results;
}
protected Model findOneBy(String parameterName, Object parameterValue)
{
List<Model> results = findBy(parameterName, parameterValue);
if (results != null && results.size() > 0) return results.get(0);
return null;
}
protected Model findOneBy(Map<String, Object> parameters)
{
List<Model> results = findBy(parameters);
if (results != null && results.size() > 0) return results.get(0);
return null;
}
public Model findOne(Long id)
{
return findOneBy("id", id);
}
public List<Model> findAll()
{
Query q = em.createQuery("select t from " + ModelClass.getSimpleName() + " t");
List<Model> results = null;
try
{
results = q.getResultList();
}
catch (Exception e)
{
return null;
}
return results;
}
public boolean save(Model model)
{
try
{
Model newModel = em.merge(model);
if (model.getId() == 0L) model.setId(newModel.getId());
}
catch (Exception e)
{
logger.error(ModelClass.getSimpleName() + "Repository: " + e.getMessage());
return false;
}
return true;
}
public void save(List<Model> models)
{
for (Model model : models)
{
save(model);
}
}
public void delete(Model model)
{
delete(model.getId());
}
public void delete(Long id)
{
beforeDelete(findOne(id));
try
{
Query q = em.createQuery("delete from " + ModelClass.getSimpleName() + " t where t.id = :id").setParameter("id", id);
q.executeUpdate();
}
catch (Exception e)
{
logger.error(ModelClass.getSimpleName() + "Repository: " + e.getMessage());
}
}
public void delete(Collection<Model> models)
{
for (Model model : models)
{
delete(model.getId());
}
}
public void deleteAll()
{
for (Model model : findAll())
{
delete(model);
}
}
public abstract void beforeDelete(Model model);
public List<Model> find(List<Long> ids)
{
List<Model> models = new ArrayList<Model>();
for (Long id : ids)
{
Model model = findOne(id);
if (model != null) models.add(model);
}
return models;
}
}
Thank you!
Related
I am using Spring Boot (v 2.4.0) with Hibernate 5.4.24 and, when trying to get some information from my database, I keep getting this error message:
org.springframework.orm.jpa.JpaSystemException: Error accessing field [private int es.uc3m.orders.model.Shoppingcart.usID] by reflection for persistent property [es.uc3m.orders.model.Shoppingcart#usID] : 1; nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private int es.uc3m.orders.model.Shoppingcart.usID] by reflection for persistent property [es.uc3m.orders.model.Shoppingcart#usID] : 1
It is kind of weird for me, because it only happens when I try to access the table Shoppingcart, since I can get informatin from the rest of the tables.
I also used the exact same entities with another project but, insetad of using Spring Boot, persistence was made with EntityManagers and it worked perfectly fine.
These are my entities:
Shoppingcart
#Entity
#NamedQuery(name="Shoppingcart.findAll", query="SELECT s FROM Shoppingcart s")
public class Shoppingcart implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int scID;
private int usID;
//bi-directional many-to-many association to Product
#ManyToMany
#JoinTable(
name="sc_has_product"
, joinColumns={
#JoinColumn(name="scID")
}
, inverseJoinColumns={
#JoinColumn(name="productID")
}
)
private List<Product> products;
//bi-directional one-to-one association to User
#OneToOne(mappedBy="shoppingcart")
private User user;
public Shoppingcart() {
}
public int getScID() {
return this.scID;
}
public void setScID(int scID) {
this.scID = scID;
}
public int getusID() {
return this.usID;
}
public void setusID(int usID) {
this.usID = usID;
}
public List<Product> getProducts() {
return this.products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
public boolean isNull() {
return getProducts().isEmpty();
}
User
#Entity
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String address;
#Column(name="card_n")
private Long cardN;
private String city;
private String country;
private int cvv;
private String email;
private String exp;
private String name;
private String pass;
private String surname1;
private String surname2;
private String typeOfUser;
#Column(name="zip_code")
private int zipCode;
//bi-directional many-to-one association to Order
#OneToMany(mappedBy="user")
private List<Orders> orders;
//bi-directional many-to-one association to Product
#OneToMany(mappedBy="user")
private List<Product> products;
//bi-directional one-to-one association to Shoppingcart
#OneToOne(cascade=CascadeType.REMOVE)
#JoinColumn(name="ID", referencedColumnName="usID", insertable=false, updatable=false)
private Shoppingcart shoppingcart;
public User() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
public Long getCardN() {
return this.cardN;
}
public void setCardN(Long cardN) {
this.cardN = cardN;
}
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 int getCvv() {
return this.cvv;
}
public void setCvv(int cvv) {
this.cvv = cvv;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getExp() {
return this.exp;
}
public void setExp(String exp) {
this.exp = exp;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getPass() {
return this.pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public String getSurname1() {
return this.surname1;
}
public void setSurname1(String surname1) {
this.surname1 = surname1;
}
public String getSurname2() {
return this.surname2;
}
public void setSurname2(String surname2) {
this.surname2 = surname2;
}
public int getZipCode() {
return this.zipCode;
}
public void setZipCode(int zipCode) {
this.zipCode = zipCode;
}
public List<Orders> getOrders() {
return this.orders;
}
public void setOrders(List<Orders> orders) {
this.orders = orders;
}
public Orders addOrder(Orders order) {
getOrders().add(order);
order.setUser(this);
return order;
}
public Orders removeOrder(Orders order) {
getOrders().remove(order);
order.setUser(null);
return order;
}
public List<Product> getProducts() {
return this.products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public Product addProduct(Product product) {
getProducts().add(product);
product.setUser(this);
return product;
}
public Product removeProduct(Product product) {
getProducts().remove(product);
product.setUser(null);
return product;
}
public Shoppingcart getShoppingcart() {
return this.shoppingcart;
}
public void setShoppingcart(Shoppingcart shoppingcart) {
this.shoppingcart = shoppingcart;
}
public String getTypeOfUser() {
return typeOfUser;
}
public void setTypeOfUser(String typeOfUser) {
this.typeOfUser = typeOfUser;
}
}
This is the ShoppingcartDAO class:
public interface ShoppingCartDAO extends CrudRepository<Shoppingcart, Integer> {
#Query("SELECT s FROM Shoppingcart s JOIN User u ON u.id = s.usID AND u.id LIKE :id")
Shoppingcart findByUser(#Param("id") int id);
#Query("SELECT s FROM Shoppingcart s")
List<Shoppingcart> findAllShoppingCart();
}
And, finally, this is my ShoppingcartController class:
#RestController
#CrossOrigin
#EnableAutoConfiguration
public class ShoppingCartController {
#Autowired
ShoppingCartDAO scDAO;
#RequestMapping(value = "sc", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<?> assignShoppingCart(#RequestBody(required = true) Shoppingcart sc) {
try {
scDAO.save(sc);
return new ResponseEntity<Void>(HttpStatus.CREATED);
} catch(Exception e) {
return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
}
}
#RequestMapping(value = "sc", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<?> getEveryShoppingCart() {
try {
List<Shoppingcart> sc = scDAO.findAllShoppingCart();
return new ResponseEntity<List<Shoppingcart>>(sc, (sc != null) ? HttpStatus.OK : HttpStatus.NOT_FOUND);
} catch(Exception e) {
System.out.println(e);
return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
}
}
}
I am really going nuts as I can´t figure out what is going on with my code, so thank you in advance if you help me.
I finally fixed it. For those of you who are wondering how, I deleted the relationships between tables that I had, ending with:
Shoppingcart:
#Entity
public class Shoppingcart implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int scID;
#Column(name = "usID")
private Integer userID;
public Shoppingcart() {
}
public int getScID() {
return this.scID;
}
public void setScID(int scID) {
this.scID = scID;
}
public Integer getUserID() {
return userID;
}
public void setUserID(Integer userID) {
this.userID = userID;
}
Product:
#Entity
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int productID;
private String category;
private String color;
private String description;
private String estadoProducto;
private String fecha;
private int orderID;
private String photo;
private double price;
private int seller;
private String sexo;
private String state = "Disponible";
private String talla;
private String title;
public Product() {
}
public int getProductID() {
return this.productID;
}
public void setProductID(int productID) {
this.productID = productID;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getColor() {
return this.color;
}
public void setColor(String color) {
this.color = color;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getEstadoProducto() {
return this.estadoProducto;
}
public void setEstadoProducto(String estadoProducto) {
this.estadoProducto = estadoProducto;
}
public String getFecha() {
return this.fecha;
}
public void setFecha(String fecha) {
this.fecha = fecha;
}
public String getPhoto() {
return this.photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public double getPrice() {
return this.price;
}
public void setPrice(double price) {
this.price = price;
}
public String getSexo() {
return this.sexo;
}
public void setSexo(String sexo) {
this.sexo = sexo;
}
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
public String getTalla() {
return this.talla;
}
public void setTalla(String talla) {
this.talla = talla;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public int getOrderID() {
return orderID;
}
public void setOrderID(int orderID) {
this.orderID = orderID;
}
public int getSeller() {
return seller;
}
public void setSeller(int seller) {
this.seller = seller;
}
With this, everything worked fine, but don't ask me why, because I don't know it.
Your Getters/Setters are wrongly implemented.
Like :
Actual :
public int getusID() {
return this.usID;
}
Expected :
public int getUsID() {
return this.usID;
}
Same with setter
Situation: I'm trying to get all persons as a rest service. But the problem is that the class Person has persons on his own(Friends). So I'm getting an infinite long json, cause of the friends connection ...
The result were I'm aiming for:
`{"naam":"Lance","voornaam":"ADAM","email":"Adam.Lance#msn.com","password":"fxSg1vSa2zzqHxuTCrDSbtp9ITlHf9ALSnS/ENFXfAA=$7vSVqz5nHZ7cEA4u6OiTBDw+CGaOJkhun4YuievZCKc=","username":"adam","status":"online","posts":[{"message":"Ik heb mijn eerste auto gekocht.","mood":"trots","when":1494603638834},"role":"ADMIN","friends":[{"username":"adamsFriend1"},{"username":"adamsFriend2"}]
So that I'm only getting the usernames of those friends. if this is not possible is there a way to exceclude those friends?
The Restcontroller:
#RestController
#RequestMapping(value = "/users")
public class UsersRestController {
private final Service service;
public UsersRestController(#Autowired Service service) {
this.service = service;
}
#RequestMapping(method = RequestMethod.GET)
public List<Person> getUsers() {
return service.getAllPersons();
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Person getUser(#PathVariable String id) {
return service.getPerson(id);
}
}
the Person class:
#Entity
public class Person {
private String naam, voornaam, email, password;
#Id
private String username;
private String status;
#ManyToMany
private Collection<Person> vrienden;
#OneToMany(orphanRemoval = true)
private Collection<Post> posts;
#Enumerated(EnumType.STRING)
private Role role;
public Person(String naam, String voornaam, String email, String password, String username) {
setNaam(naam);
setEmail(email);
setStatus("online");
setVoornaam(voornaam);
setPassword(password);
setUsername(username);
vrienden = new HashSet<>();
posts = new HashSet<>();
role = Role.USER;
}
public static void addFriend(Person a, Person b) {
a.addFriend(b);
b.addFriend(a);
}
private void addFriend(Person b) {
this.vrienden.add(b);
}
public static void deleteFriend(Person a, Person b) {
a.deleteFriend(b);
b.deleteFriend(a);
}
private void deleteFriend(Person a) {
this.vrienden.remove(a);
}
public Collection<Person> getFriends() {
return vrienden;
}
public Role getRole() {
return this.role;
}
public void setRole(Role role) {
this.role = role;
}
#NotNull(message = "{error.no.name}")
#Size(min = 2, message = "{error.invalid.namesize}")
public String getNaam() {
return naam;
}
public void setNaam(String naam) {
this.naam = naam;
}
#NotNull(message = "{error.no.surnaam}")
#Size(min = 2, message = "{error.invalid.surnamesize}")
public String getVoornaam() {
return voornaam;
}
public void setVoornaam(String voornaam) {
this.voornaam = voornaam;
}
#NotNull(message = "{error.no.email}")
#Email(message = "{error.invalid.email}")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#NotNull(message = "{error.no.status}")
#Size(min = 1, message = "{error.no.valid.status}")
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
#NotNull(message = "{error.no.username}")
#Size(min = 2, message = "{error.invalid.usernamesize}")
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = Password.getSaltedHash(password);
}
public boolean isPasswordCorrect(String password) {
boolean result = false;
result = Password.check(password, this.password);
return result;
}
#NotNull(message = "{error.no.password}")
#Size(min = 2, message = "{error.invalid.usernamesize}")
public String getPassword() {
return this.password;
}
public void addPost(Post p) {
if (p == null) {
throw new DomainException("Post is null");
}
posts.add(p);
}
public void deletePost(Post p) {
if (p == null) {
throw new DomainException("Post is null");
}
posts.remove(p);
}
public Collection<Post> getPosts() {
return posts;
}
#Override
public int hashCode() {
int hash = 3;
hash = 59 * hash + Objects.hashCode(this.username);
return hash;
}
public void setHashedPassword(String password) {
this.password = password;
}
}
just made a wrapper class for Person. There is probably a better way... .
but if you intrested this is the wrapper class:
public class WrapPerson {
private String naam;
private String voornaam;
private String email;
private String username;
private String status;
private Collection<String> vrienden;
private Collection<Post> posts;
public WrapPerson(Person person) {
setEmail(person.getEmail());
setNaam(person.getNaam());
setPosts(person.getPosts());
setStatus(person.getStatus());
setUsername(person.getUsername());
setVoornaam(person.getVoornaam());
this.vrienden = new ArrayList<>();
for (Person p : person.getFriends()) {
this.vrienden.add(p.getUsername());
}
}
public String getNaam() {
return naam;
}
public void setNaam(String naam) {
this.naam = naam;
}
public String getVoornaam() {
return voornaam;
}
public void setVoornaam(String voornaam) {
this.voornaam = voornaam;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Collection<String> getVrienden() {
return vrienden;
}
public void setVrienden(Collection<String> vrienden) {
this.vrienden = vrienden;
}
public Collection<Post> getPosts() {
return posts;
}
public void setPosts(Collection<Post> posts) {
this.posts = posts;
}
}
`
Using Hibernate 3.6.0
I'm having a real hard time understanding hibernate. I keep running into this issue with lazy initialization exception.
I have an Event entity with a one-to-many relationship with RSVP. When a run a test get back a list of events it works. But when I'm making the call in my controller in order to return it as json, I run into this lazy init error.
This is my event class
#Entity
#Table(name = "EVENT")
public class Event implements Serializable {
#SequenceGenerator(name="event", sequenceName="EVENT_PK_SEQ")
#GeneratedValue(generator="event",strategy=GenerationType.SEQUENCE)
#Id
#Column(name = "EVENT_ID")
private int id;
#Column(name = "DATE_TIME")
private Date date;
#Column(name = "EVENT_NAME")
private String name;
#Column(name = "EVENT_PARTICIPANT_LIMIT")
private int limit;
#Column(name = "EVENT_VISIBILITY")
private boolean visibilty;
#Column(name = "EVENT_LOCATION")
private String location;
#Column(name = "EVENT_DESCRIPTION")
private String description;
#OneToOne(cascade=CascadeType.REMOVE, fetch= FetchType.EAGER)
private User author;
private Date create_date;
#OneToOne(cascade=CascadeType.REMOVE, fetch= FetchType.EAGER)
private EventType eventType;
#OneToOne(cascade=CascadeType.REMOVE, fetch= FetchType.EAGER)
private EventClass eventClass;
#OneToMany(cascade = CascadeType.ALL)
private Set<RSVP> rsvps = new HashSet<RSVP>();
#ManyToMany(mappedBy="event")
private Set<Group> groups = new HashSet<Group>();
public Event(int id, Date date, String name, int limit, boolean visibilty, String location, String description,
User author, Date create_date, EventType eventType, EventClass eventClass) {
super();
this.id = id;
this.date = date;
this.name = name;
this.limit = limit;
this.visibilty = visibilty;
this.location = location;
this.description = description;
this.author = author;
this.create_date = create_date;
this.eventType = eventType;
this.eventClass = eventClass;
}
public Event(){
super();
}
#Override
public String toString() {
return "Event [id=" + id + ", date=" + date + ", name=" + name + ", limit=" + limit + ", visibilty=" + visibilty
+ ", location=" + location + ", description=" + description + ", author=" + author + ", create_date="
+ create_date + ", eventType=" + eventType + ", eventClass=" + eventClass + ", rsvps=" + rsvps
+ ", groups=" + groups + "]";
}
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
this.author = author;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public boolean isVisibilty() {
return visibilty;
}
public void setVisibilty(boolean visibilty) {
this.visibilty = visibilty;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getCreate_date() {
return create_date;
}
public void setCreate_date(Date create_date) {
this.create_date = create_date;
}
public EventType getEventType() {
return eventType;
}
public void setEventType(EventType eventType) {
this.eventType = eventType;
}
public EventClass getEventClass() {
return eventClass;
}
public void setEventClass(EventClass eventClass) {
this.eventClass = eventClass;
}
public Set<RSVP> getRsvps() {
return rsvps;
}
public void setRsvps(Set<RSVP> rsvps) {
this.rsvps = rsvps;
}
public Set<Group> getGroups() {
return groups;
}
public void setGroups(Set<Group> groups) {
this.groups = groups;
}
}
My RSVP
#Entity
#Table(name="RSVP")
public class RSVP {
#Id
#Column(name="RSVP_ID")
#SequenceGenerator(name="rsvp", sequenceName="RSVP_PK_SEQ")
#GeneratedValue(generator="rsvp",strategy=GenerationType.SEQUENCE)
private int rsvpId;
#OneToOne(cascade=CascadeType.REMOVE, fetch= FetchType.EAGER)
#JoinColumn(name="STATUS_ID")
private RSVPStatus status;
#ManyToOne(cascade=CascadeType.REMOVE)
#JoinColumn(name="USER_ID")
private User user;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="EVENT_ID")
private Event event;
public RSVP(int rsvpId, RSVPStatus status, User user, Event event) {
super();
this.rsvpId = rsvpId;
this.status = status;
this.user = user;
this.event = event;
}
public RSVP() {
}
#Override
public String toString() {
return "RSVP [rsvpId=" + rsvpId + ", status=" + status + ", user=" + user + ", event=" + event + "]";
}
public int getRsvpId() {
return rsvpId;
}
public void setRsvpId(int rsvpId) {
this.rsvpId = rsvpId;
}
public RSVPStatus getStatus() {
return status;
}
public void setStatus(RSVPStatus status) {
this.status = status;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Event getEvent() {
return event;
}
public void setEvent(Event event) {
this.event = event;
}
}
MY controller
public class MyController {
private static SessionFactory sf = HibernateUtils.getSessionFactory();
private DataFacade df = new DataFacade(sf);
#RequestMapping(value="home", method=RequestMethod.GET,
consumes= MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<List<Event>> getUserCal(){
DataFacade df = new DataFacade(sf);
List<Event> events= df.getAllEventsByAuthor(1);
for(Event e:events){
System.out.println(e);
}
return new ResponseEntity<List<Event>>(events,HttpStatus.OK);
}
}
Your RSVP collection is fetched lazily. (If you don't specify a fetch type, the default is lazy). You need to change it to eager if you are planning to access it after the Hibernate session is closed:
#OneToMany(cascade = CascadeType.ALL, fetch= FetchType.EAGER)
private Set<RSVP> rsvps = new HashSet<RSVP>();
I have an application which accesses an oracle-db which is storing contacts in a table. create, read and update is working fine. But delete won't work only sometimes for some weird reason.
When i start my application, i load all current contacts from my db and put them in a javafx-table. i let hibernate show me all it's sql and thats all it did until here. It only did once a select. Now if i directly start to delete contacts it works fine for 3-4 contacts and then i get an error which tells me, that hibernate tried to run an update-statement where it used as id null. why is hibernate doing this?
this is total nonsense. i double and tripple checked it and there is no db-action running between the select statement and the deletes. why does hibernate do an update in the middle of nowhere without any reason when i tell it to delete?
Here you see all coude and information you can possibly need to understand my situation
public void refresh() {
List<OrganisationContact> allContacts = EntityStore.ORGA_CON_REPO
.readAllWithDetails();
contactTable.getItems().setAll(allContacts);
}
This is the method in my repository
#Override
public List<OrganisationContact> readAllWithDetails() {
try {
JPAJinqStream<Contact> stream = getStreamForTable(Contact.class);
List<OrganisationContact> organisationContactList = new ArrayList<OrganisationContact>();
try {
stream.forEach(con -> organisationContactList
.add(new OrganisationContact(con)));
} catch (javax.persistence.PersistenceException exception) {
NoReplyFromDatabaseException.showErrorDialog();
throw new NoReplyFromDatabaseException(exception);
}
stream.close();
return organisationContactList;
} catch (javax.persistence.PersistenceException exception) {
NoReplyFromDatabaseException.showErrorDialog();
throw new NoReplyFromDatabaseException(exception);
}
}
This is the method in my abstract repository my normal repository is using
protected <TableEntity>JPAJinqStream<TableEntity> getStreamForTable(final Class<TableEntity> pEntityClass) {
if (this.manager != null && this.factory != null && this.provider != null) {
if (this.manager.isOpen() && this.factory.isOpen()) {
return this.provider.streamAll(this.manager, pEntityClass);
}
}
return null;
}
manager is an instance of EntityMananger
factory is an instance of EntityManagerFactory
provider is an instance of JinqJPAStreamProvider
This is the code which is executed when you delete a contact
#FXML
public void onDelete() {
EntityStore.ORGA_CON_REPO.delete(EntityStore.CURRENT_CONTACT);
if (!UnitOfWork.closeTransaction(EntityStore.ORGA_CON_REPO, true)) {
// error occured
}
// ignore that stuff
EntityStore.CURRENT_CONTACT = null;
ModeManager.clearMode();
ModeManager.refreshTable();
}
ORGA_CON_REPO is my repository from above
UnitOfWork knows all existing repositories (in this case only 1 exists) and handles it's transactions
This is my UnitOfWork class
public final class UnitOfWork {
private static final Map<AbstractRepository<?>, EntityManager> units = new HashMap<AbstractRepository<?>, EntityManager>();
private UnitOfWork() {
}
/* PUBLIC */
/**
* Executes a commit/rollback and closes the transaction for the passed
* repository.
*
* #param pRepository
* The repository the transaction belongs to.
* #param pCommit
* If this parameter is <code>true</code>, the transaction will
* be commited before closing. If it is <code>false</code>, the
* transaction will be rolled back before closing.
* #return true if the transaction has been closed successfully, false if an error occured while closing or the manager was null
*/
public synchronized static boolean closeTransaction(
final AbstractRepository<?> pRepository, final boolean pCommit) {
EntityManager manager = units.get(pRepository);
if (manager != null) {
try {
EntityTransaction t = manager.getTransaction();
if (t.isActive()) {
if (pCommit) {
t.commit();
} else {
t.rollback();
}
}
units.remove(pRepository);
return true;
} catch (PersistenceException pException) {
pRepository.resetManager(false);
units.remove(pRepository);
// TODO: log and throw
}
}
return false;
}
/* PROTECTED */
/**
* Starts a new transaction in a new unit of work.
*
* #param pRepository
* The repository the transaction belongs to.
* #param pManager
* The EntityManager of the passed repository.
* #return <code>true</code> if the transaction has been started
* successfully, <code>false</code> if the manager is closed or one
* of the parameters is null.
*/
protected synchronized static boolean beginTransaction(
final AbstractRepository<?> pRepository,
final EntityManager pManager) {
if (pRepository != null || pManager != null) {
if (pManager.isOpen()) {
if (!units.containsKey(pRepository)) {
EntityTransaction t = pManager.getTransaction();
if (!t.isActive()) {
t.begin();
}
units.put(pRepository, pManager);
}
return true;
}
}
return false;
}
}
This is the delete method of my repository
#Override
public boolean delete(OrganisationContact pEntity) {
Contact contactEntity = pEntity.getContact();
return remove(contactEntity);
}
which is using the method of my abstract repository
protected boolean remove(final Object pEntity) {
if (this.canManagerExecute(pEntity)) {
if (this.beginTransaction()) {
this.manager.remove(pEntity);
return true;
}
}
return false;
}
private boolean canManagerExecute(final Object pEntity) {
if (this.manager != null && pEntity != null) {
return this.manager.isOpen();
}
return false;
}
which is using hibernate.
And this are my entities
#Entity
#Table(schema = "reskonverw")
public class Contact {
#Column(name = "phonenumber")
private String phoneNumber;
#Column(name = "firstname")
private String firstName;
#Column(name = "surname")
private String surname;
#Column(name = "email")
private String email;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name="id")
private int id;
#ManyToOne(cascade = CascadeType.ALL)
private Organisation organisation;
#ManyToOne(cascade = CascadeType.ALL)
private Role role;
public Contact() {
}
public Contact(String phoneNumber, String firstName, String surname,
String email, Organisation organisation, Role role) {
this.phoneNumber = phoneNumber;
this.firstName = firstName;
this.surname = surname;
this.email = email;
this.organisation = organisation;
this.role = role;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Organisation getOrganisation() {
return organisation;
}
public void setRole(final Role pRole) {
role = pRole;
}
public Role getRole() {
return role;
}
public void setOrganisation(Organisation organisation) {
this.organisation = organisation;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Override
public String toString() {
return new StringBuilder(surname).append(", ").append(firstName)
.toString();
}
}
#Entity
#Table(schema = "reskonverw")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private int id;
private String name;
public Country() {
}
public Country(String cName) {
this.name = cName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return name;
}
}
#Entity
#Table(schema = "reskonverw")
public class Organisation {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private int id;
private String name;
private String zipcode;
private String housenumber;
private String city;
private String street;
#ManyToOne(cascade = CascadeType.ALL)
private Country country;
public Organisation() {
}
public Organisation(String name, String zipcode, String housenumber,
String city, String street, Country country) {
this.name = name;
this.zipcode = zipcode;
this.housenumber = housenumber;
this.city = city;
this.street = street;
this.country = country;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public String getHousenumber() {
return housenumber;
}
public void setHousenumber(String housenumber) {
this.housenumber = housenumber;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
#Override
public String toString() {
return name;
}
}
#Entity
#Table(schema = "reskonverw")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private int id;
private String description;
public Role() {
}
public Role(String rDescription) {
this.description = rDescription;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public String toString() {
return description;
}
}
My session bean which is used to be displayed in the javafx table
public class OrganisationContact {
private Contact contact;
public OrganisationContact(Contact contact) {
this.contact = contact;
}
/* Entities */
public Organisation getOrganisation() {
return contact.getOrganisation();
}
public void setOrganisation(Organisation organisation) {
contact.setOrganisation(organisation);
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public Role getRole() {
return contact.getRole();
}
public void setRole(final Role pRole) {
contact.setRole(pRole);
}
public Country getCountry() {
return contact.getOrganisation().getCountry();
}
public void setCountry(final Country pCountry) {
contact.getOrganisation().setCountry(pCountry);
}
/* EntityStats */
// Organisation
public String getOrganisationName() {
return contact.getOrganisation().getName();
}
public void setOrganisationName(final String pName) {
contact.getOrganisation().setName(pName);
}
public String getOrganisationZipcode() {
return contact.getOrganisation().getZipcode();
}
public void setOrganisationZipcode(final String pZipcode) {
contact.getOrganisation().setZipcode(pZipcode);
}
public String getOrganisationHousenumber() {
return contact.getOrganisation().getHousenumber();
}
public void setOrganisationHouseNumber(final String pHouseNumber) {
contact.getOrganisation().setHousenumber(pHouseNumber);
}
public String getOrganisationCity() {
return contact.getOrganisation().getCity();
}
public void setOrganisationCity(final String pCity) {
contact.getOrganisation().setCity(pCity);
}
public String getOrganisationStreet() {
return contact.getOrganisation().getStreet();
}
public void setOrganisationStreet(final String pStreet) {
contact.getOrganisation().setStreet(pStreet);
}
// Contact
public String getFirstName() {
return contact.getFirstName();
}
public void setFirstName(final String pFirstName) {
contact.setFirstName(pFirstName);
}
public String getSurname() {
return contact.getSurname();
}
public void setSurname(final String pSurname) {
contact.setSurname(pSurname);
}
public String getEmail() {
return contact.getEmail();
}
public void setEmail(final String pEmail) {
contact.setEmail(pEmail);
}
public String getPhoneNumber() {
return contact.getPhoneNumber();
}
public void setPhoneNumber(final String pPhoneNumber) {
contact.setPhoneNumber(pPhoneNumber);
}
// Country
public String getOrganisationCountryName() {
return contact.getOrganisation().getCountry().getName();
}
// Role
public String getRoleDescription() {
return contact.getRole().getDescription();
}
public void setRoleDescription(final String pDescription) {
contact.getRole().setDescription(pDescription);
}
}
EDIT: Here the sql hibernate prints on my console first when it does the select at the programmstart:
Hibernate:
select
*
from
( select
contact0_.id as id1_0_,
contact0_.email as email2_0_,
contact0_.firstname as firstname3_0_,
contact0_.organisation_id as organisation_id6_0_,
contact0_.phonenumber as phonenumber4_0_,
contact0_.role_id as role_id7_0_,
contact0_.surname as surname5_0_
from
reskonverw.Contact contact0_ )
where
rownum <= ?
Hibernate:
select
organisati0_.id as id1_2_0_,
organisati0_.city as city2_2_0_,
organisati0_.country_id as country_id7_2_0_,
organisati0_.housenumber as housenumber3_2_0_,
organisati0_.name as name4_2_0_,
organisati0_.street as street5_2_0_,
organisati0_.zipcode as zipcode6_2_0_,
country1_.id as id1_1_1_,
country1_.name as name2_1_1_
from
reskonverw.Organisation organisati0_
left outer join
reskonverw.Country country1_
on organisati0_.country_id=country1_.id
where
organisati0_.id=?
Hibernate:
select
role0_.id as id1_3_0_,
role0_.description as description2_3_0_
from
reskonverw.Role role0_
where
role0_.id=?
Here the sql hibernate prints on my console when it does the delete at the buttonclick (select because i update all entities afterwards because there are multiple clients):
Hibernate:
delete
from
reskonverw.Contact
where
id=?
Hibernate:
select
*
from
( select
contact0_.id as id1_0_,
contact0_.email as email2_0_,
contact0_.firstname as firstname3_0_,
contact0_.organisation_id as organisation_id6_0_,
contact0_.phonenumber as phonenumber4_0_,
contact0_.role_id as role_id7_0_,
contact0_.surname as surname5_0_
from
reskonverw.Contact contact0_ )
where
rownum <= ?
Here the sql hibernate prints on my console when it does an update instead of a delete at the buttonclick (no select because it crashes before):
Hibernate:
update
reskonverw.Contact
set
email=?,
firstname=?,
organisation_id=?,
phonenumber=?,
role_id=?,
surname=?
where
id=?
Jul 08, 2015 8:05:12 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1407, SQLState: 72000
Jul 08, 2015 8:05:12 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: ORA-01407: Aktualisieren von ("RESKONVERW"."CONTACT"."ORGANISATION_ID") zu NULL nicht möglich
For not german ppl, 'ERROR: ORA-01407: Aktualisieren von ("RESKONVERW"."CONTACT"."ORGANISATION_ID") zu NULL nicht möglich' means 'error - setting resconverw.contact.organisation_id to null not possible
Contact has a foreginkey to Organisation. It is linked by the id of the Organisation. When i delete the Contact, Hibernate sometimes tries to set the foreginkey to null before deleting it. Not always for some reason i couldn't figure out yet. In my db i had setup a constraint which prevent the foregin key from becomeing null. And that is why the update failed and i got an exception. I removed the constraint and since then it is working.
Thanks all for the help
In a web-service i have the following function which retreives some infos of a doctor and his patient based on patient's phone:
public String findDoctorOfPatient(String phone) {
AnnotationConfiguration config = new AnnotationConfiguration();
config.configure("hibernate.cfg.xml");
SessionFactory factory = config.buildSessionFactory();
Session session = factory.openSession();
session.beginTransaction();
Criteria query = session.createCriteria(doctor.class);
query.createCriteria("patients", "p");
query.add(Restrictions.eq("p.phone", phone));
List<doctor> doctorList = (ArrayList<doctor>) query.list();
session.getTransaction().commit();
String answear = "";
for (doctor d : doctorList) {
answear = answear.concat("docPhone" + d.getPhone() + "docEmail"
+ d.getEmail() + "patDia"
+ d.getPatients().iterator().next().getDiastolic()
+ "patSys"
+ d.getPatients().iterator().next().getSystolic());
}
if (doctorList.isEmpty()) {
session.close();
factory.close();
return "No Doctor!";
} else {
session.close();
factory.close();
return answear;
}
}
The problem is when i have one patient is ok , but when i add second patient it gives me the details of last patient despite i have set to criteria tha firt's patient phone!
I have 2 tables:
1.doctor(id,username,password,phone,email)
2.patient(id,name,surname,phone,systolic,diastolic,doctorid(FK refers to doctor.id))
I have configured properly the hibernate.cfg.xml.
And i have set the class for doctor and patient:
#Entity
public class doctor {
#Id
private int id;
private String username;
private String password;
private String phone;
private String email;
#OneToMany(targetEntity = patient.class, cascade = CascadeType.ALL, mappedBy = "doctor")
#Cascade(value = org.hibernate.annotations.CascadeType.ALL)
private Collection<patient> patients = new ArrayList<patient>();
public Collection<patient> getPatients() {
return patients;
}
public void setPatients(Collection<patient> patients) {
this.patients = patients;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
#Entity
public class patient {
#Id
private int id;
private String name;
private String surname;
private String phone;
private int systolic;
private int diastolic;
#ManyToOne
private doctor doctor;
public doctor getDoctor() {
return doctor;
}
public void setDoctor(doctor doctor) {
this.doctor = doctor;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public int getSystolic() {
return systolic;
}
public void setSystolic(int systolic) {
this.systolic = systolic;
}
public int getDiastolic() {
return diastolic;
}
public void setDiastolic(int diastolic) {
this.diastolic = diastolic;
}
}
In this web-service the response is always the same (given the mobile number) .
It gives me always the patSys=130 and patDia=80 which are the second's patient info!.Something must be wrong in the webservice but to me all seems ok!
You need to create Criteria object on Patient and no need to obtain transaction here.
Criteria query = session.createCriteria(Patient.class)
.add(Restrictions.eq("phone", phone));
List<Patient> patList = (ArrayList<Patient>) query.list();
String result="";
if(!patList.isEmpty()) {
Patient patient=patList.get(0);
result="Doc Phone : " + patient.getDoctor().getPhone();
}
return result;