EntityNotFoundException unable to find entity with id X after using MappedSuperclass - java

Environment:
javaee 7
java 8
jpa 2
I got the error EntityNotFoundException when I make a query of Moviment and automatically tries to load the associated Espai after I have modifed Espai class to separate id and version in a separate class with the annotation #MappedSuperclass.
I can suspect that it is something related with equals() and hashCode() methods but I have not been able to figure out the problem.
Espai that works fine
#Entity
#Table(name = "a_espai")
public class Espai implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String nom;
private Integer version;
#ManyToOne
#JoinColumn(name = "idServei", referencedColumnName = "id")
private Servei servei;
...
#Override
public int hashCode() {
int hash = servei == null ? 1 : servei.getId();
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Espai)) {
return false;
}
Espai other = (Espai) obj;
return id != null && id.equals(other.getId());
}
}
Espai after change that provokes the error
#Entity
#Table(name = "a_espai")
public class Espai extends BaseEntity implements Serializable {
private String nom;
#ManyToOne
#JoinColumn(name = "idServei", referencedColumnName = "id")
private Servei servei;
#Override
public int hashCode() {
int hash = 0;
if (servei == null) {
return hash;
} else {
return servei.getId();
}
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Espai)) {
return false;
}
Espai other = (Espai) obj;
return getId() != null && getId().equals(other.getId());
}
}
Moviment class where Espai gets the error on eager loading
#Entity
#Table(name = "t_moviment")
public class Moviment extends BaseEntity implements Serializable {
private LocalDate dataInici;
private LocalDate dataFi;
private String observacio;
#ManyToOne
#Basic(optional = false)
#JoinColumn(name = "idEspai", referencedColumnName = "id")
private Espai espai;
...
}
**Espai before change that provokes the error**
#MappedSuperclass
public class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Version
protected Integer version;
public Integer getId() {
return id;
}
}

Related

how resolve ConstraintViolationException Identity strategy in hibernate problem?

I'm working an application with java. I am getting this error:
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-54) DB2 SQL Error:
SQLCODE=-407, SQLSTATE=23502, SQLERRMC=TBSPACEID=2, TABLEID=1298, COLNO=0,
with this exception:
exception occurred: -- javax.persistence.PersistenceException:
org.hibernate.exception.ConstraintViolationException: could not execute statement
I looked for a solution and I getting this docs:
https://www.ibm.com/docs/en/cfm/2.0.0.3?topic=job-common-sql-errors-during-data-import
it helps me to get which column has the error. it's my primary key.
My primary generated my Station entity is:
#Named
#Entity
#Table(name = "STATION")
#AttributeOverride(name = "id", column = #Column(name = "PK_STATION_ID"))
public class Station extends AbstractEntity {}
my AbstractEntity is:
#MappedSuperclass
public abstract class AbstractEntity extends AbstractEntityWithoutId {
/**
*
*/
private static final long serialVersionUID = 8088586545483293731L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
public String getRefObject() {
return String.valueOf(super.hashCode());
}
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
AbstractEntity that = (AbstractEntity) other;
if (this.id == null || that.id == null) {
return super.equals(other);
}
return Objects.equals(id, that.id);
}
#Override
public int hashCode() {
if (id == null) {
return super.hashCode();
}
return Objects.hash(id);
}
}
How to resolve that? thanks in advance.

Entity's Set contains method is not working

I am trying to save entity with relational other entity.
Here's my Entities
#MappedSuperclass
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
BaseEntity() {
}
protected BaseEntity(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BaseEntity that = (BaseEntity) o;
return id.equals(that.id);
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "auth_type")
public abstract class BlogUser extends BaseEntity {
#ManyToOne
#JoinColumn(name = "user_id", nullable = false, updatable = false)
private User user;
#ManyToOne
#JoinColumn(name = "blog_id", nullable = false, updatable = false)
private Blog blog;
BlogUser() {
}
protected BlogUser(User user, Blog blog) {
this.user = user;
this.blog = blog;
}
public User getUser() {
return user;
}
public Blog getBlog() {
return blog;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BlogUser)) return false;
BlogUser blogUser = (BlogUser) o;
return user.equals(blogUser.getUser()) && blog.equals(blogUser.getBlog());
}
#Override
public int hashCode() {
return Objects.hash(user, blog);
}
}
#Entity
#DiscriminatorValue("ADMIN")
public class BlogAdmin extends BlogUser {
public BlogAdmin(User user, Blog blog) {
super(user, blog);
}
}
#Entity
#DiscriminatorValue("INVITED")
public class BlogInvitedUser extends BlogUser {
public BlogInvitedUser(User user, Blog blog) {
super(user, blog);
}
}
#Entity
public class Blog extends BaseEntity {
//fields
#OneToMany(mappedBy = "blog", cascade = CascadeType.PERSIST)
private Set<BlogUser> blogUsers = new HashSet<>();
Blog() {
}
public Blog(String name, String introduce) {
this.name = name;
this.introduce = introduce;
}
//other field's getters
public Set<BlogUser> getBlogUsers() {
return blogUsers;
}
public void addBlogUser(BlogUser blogUser) {
if (blogUsers.contains(blogUser)) { // This is not working
throw new DataIntegrityViolationException("blog's users is duplicated");
}
blogUsers.add(blogUser);
}
}
When Saving Blog Entity with blog user that BlogUser' child entity, Blog's addBlogUser method is not working!
I know Set works by hashCode method.
So, I override BlogUser entity's hashCode and equals method.
But Testing result is weird.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ApplicationConfiguration.class, loader = AnnotationConfigContextLoader.class)
public class BlogUserTest {
#Autowired
private UserDao userDao;
#Autowired
private BlogDao blogDao;
#Test
#Transactional
public void WhenAddBlogUsers_GivenDifferntTypeSameUserAndBlogAfterPersistBlog_ThrowDataIntegrityViolationException() {
User user = new User("name", "nick", "email", null);
userDao.save(user);
Blog blog = new Blog("test", null);
BlogUser admin = new BlogAdmin(user, blog);
blog.addBlogUser(admin);
blogDao.save(blog);
System.out.println(blog.getBlogUsers().iterator().next().hashCode() == new BlogInvitedUser(user, blog).hashCode()); // true
System.out.println(blog.getBlogUsers().contains(new BlogInvitedUser(user, blog))); // false
}
}
In fact, while testing, I knew that It works if EntityManager persist that.
I wonder what is happening internally.
Any answer is welcome.

insertable=false puts null into my value, but true gives an error (many to many relationship)

I have 3 tables. Hospitals and doctors. The 3rd table is a junction table of both that contains id,ids of 2 other tables as foreign keys and few other columns. When trying to put record to a junction table I got an error that one of foreign keys have to be set with insertable=false. However when I set it like this then I get that the value can't be null (since my database requires that field).I'm stuck and can't go any further with those 2 errors.
If I manage to avoid those 2 errors then I get an erorr that there is an unknown column in the field list.
Doctors entity:
#Entity
#Table(name = "doctors")
public class Doctors implements Serializable {
private Integer id;
private String name;
private String surname;
private String title;
private String licenseNumber;
private String phone;
private String email;
private String nationality;
private String speciality;
private LocalDate dateOfBirth;
private Boolean isATeacher;
private List<HospitalDoctors> hospitalDoctors = new LinkedList<>();
//consturctors
#Id
#GenericGenerator(name = "generator", strategy = "increment")
#GeneratedValue(generator = "generator")
#Column(name = "Idd", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
//setters and getters for rest of the fields with #column annotations on getters
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.doctor", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE})
public List<HospitalDoctors> getHospitalDoctors() {
return hospitalDoctors;
}
public void setHospitalDoctors(List<HospitalDoctors> hospitalDoctors) {
this.hospitalDoctors = hospitalDoctors;
}
Hospitals entity:
#Entity
#Table(name = "hospitals")
public class Hospitals implements Serializable {
private Integer id;
private String name;
private String country;
private String town;
private String street;
private String postalCode;
private String phoneNumber;
private String faxNumber;
private Integer numberOfAmbulances;
private Boolean helicopterAccess;
private Boolean teachingHospital;
private List<HospitalDoctors> hospitalDoctors = new LinkedList<>();
//constructors
#Id
#GenericGenerator(name = "generator", strategy = "increment")
#GeneratedValue(generator = "generator")
#Column(name = "Idh", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
//getters setters with #column annotations over getters
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.hospital", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE})
public List<HospitalDoctors> getHospitalDoctors() {
return this.hospitalDoctors;
}
public void setHospitalDoctors(List<HospitalDoctors> hospitalDoctors) {
this.hospitalDoctors = hospitalDoctors;
}
Junction table entity:
#Entity
#Table(name = "hospitaldoctors")
#AssociationOverrides({
#AssociationOverride(name = "pk.hospital",
joinColumns = #JoinColumn(name = "Idh")),
#AssociationOverride(name = "pk.doctor",
joinColumns = #JoinColumn(name = "Idd"))
})
public class HospitalDoctors implements Serializable {
private Integer id;
private Integer idH;
private Integer idD;
private HospitalDoctorsId pk = new HospitalDoctorsId();
private LocalDate contractStartDate;
private LocalDate contractEndDate;
private String position;
private Boolean supervisor;
private Boolean partTime;
//constructors
#Column(name ="Idhos")
public Integer getIdH() {
return this.idH;
}
public void setIdH(Integer idH) {
this.idH = idH;
}
#Column(name ="Iddoc")
public Integer getIdD() {
return this.idD;
}
public void setIdD(Integer idD) {
this.idD = idD;
}
#EmbeddedId
public HospitalDoctorsId getPk() {
return pk;
}
public void setPk(HospitalDoctorsId pk) {
this.pk = pk;
}
#Transient
public Hospitals getHospital(){
return getPk().getHospital();
}
public void setHospital(Hospitals hospital){
getPk().setHospital(hospital);
}
#Transient
public Doctors getDoctor(){
return getPk().getDoctor();
}
public void setDoctor(Doctors doctor){
getPk().setDoctor(doctor);
}
//rest of the setters getters with #Column
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HospitalDoctors that = (HospitalDoctors) o;
if(getPk() != null?!getPk().equals(that.getPk()) : that.getPk() != null) return false;
return true;
}
#Override
public int hashCode() {
return (getPk() != null? getPk().hashCode() : 0);
}
Junction table Id:
#Embeddable
public class HospitalDoctorsId implements Serializable {
private Hospitals hospital;
private Doctors doctor;
#ManyToOne
public Hospitals getHospital() {
return hospital;
}
public void setHospital(Hospitals hospital) {
this.hospital = hospital;
}
#ManyToOne
public Doctors getDoctor() {
return doctor;
}
public void setDoctor(Doctors doctor) {
this.doctor = doctor;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HospitalDoctorsId that = (HospitalDoctorsId) o;
if(hospital != null?!hospital.equals(that.hospital) : that.hospital != null) return false;
if(doctor != null?!doctor.equals(that.doctor) : that.doctor != null) return false;
return true;
}
#Override
public int hashCode() {
int result;
result = (hospital != null? hospital.hashCode() : 0);
result = 31* result + (doctor != null? doctor.hashCode() : 0);
return result;
}
}
I expected to be able to add records to junction table in data base in form fields I have foreign keys for hospital and doctors id to put in as well as other fields. Unfortunately I get either error that say to put foreign keys columns idD and idH as insertable, updatable false which leads to null value being passed which gives another error. When I solve those errors I get the error:
java.sql.SQLSyntaxErrorException: Unknown column 'hospitaldo0_.Idd' in 'field list'when trying to display records nad unknown column Idd when trying to add record (displaying works when Im getting insertable error or null value error. adding never works)
If I remember correctly, you need to have a single #ManyToMany relation rather than two #OneToMany relations.

Saving entity tries to insert new record instead of merging with previous record

When a parent entity is persisted/merged via saveAndFlush, it tries to insert a new record for the child entity instead of finding/merging the existing record. This causes a SQLIntegrityConstraintViolationException error. I have also tried pulling the existing entity directly via the DAO, setting that to be the field in the parent entity, and then saving and flushing, and it still tries to insert a new record for the child entity field.
Any help is greatly appreciated!
Child Entity
#Entity
#Table(name = "DROPDOWN_TYPE", uniqueConstraints = {
#UniqueConstraint(columnNames = { "DROPDOWN_TYPE_TXT" }, name = "DROPDOWN_TYPE_TXT_UK") })
public class DropdownType {
#Id
#Column(name = "DROPDOWN_TYPE_TXT")
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DropdownType that = (DropdownType) o;
return text.equals(that.text);
}
#Override
public int hashCode() {
return text.hashCode();
}
}
Parent Entity
#Entity
#Table(name = "DROPDOWN", uniqueConstraints = {
#UniqueConstraint(columnNames = { "DROPDOWN_TXT", "DROPDOWN_TYPE_TXT" }, name = "DROPDOWN_UK") })
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Dropdown {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "DROPDOWN_OPTION_ID_GENERATOR")
#SequenceGenerator(allocationSize = 1, name = "DROPDOWN_OPTION_ID_GENERATOR", sequenceName = "DROPDOWN_OPTION_ID_SQ")
#Column(name = "DROPDOWN_OPTION_ID")
private Long id;
#ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST })
#JoinColumn(name = "DROPDOWN_TYPE_TXT", foreignKey = #ForeignKey(name = "DROPDOWN_TYPE_TXT_FK"))
private DropdownType dropdownType;
#Column(name = "DROPDOWN_TXT")
private String text;
#Column(name = "ACTIVE_FLG")
private Boolean active;
#Column(name = "LEGACY_FLG")
private Boolean legacy;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public DropdownType getDropdownType() {
return dropdownType;
}
public void setDropdownType(DropdownType dropdownType) {
this.dropdownType = dropdownType;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Boolean isActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
public Boolean isLegacy() {
return legacy;
}
public void setLegacy(Boolean legacy) {
this.legacy = legacy;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dropdown dropdown = (Dropdown) o;
return dropdownType.equals(dropdown.dropdownType) && text.equals(dropdown.text);
}
#Override
public int hashCode() {
int result = dropdownType != null ? dropdownType.hashCode() : 0;
result = 31 * result + (text != null ? text.hashCode() : 0);
return result;
}
}
If you are using hibernate as your JPA provider, be careful when you override equals and hashcode -- see this post
It may be, that your JPA provider does not consider your entities to be equal as loaded entities can be some CGLIB proxies in reality (probably better to use instanceof than to compare classes).

hibernate how to extend one entity to all the entities

I have two fields that should appear in each table. So I wanted to create an entity that will hold these fields and the rest of my entities inherited these fields
But when I run the query I get the error - org.hibernate.QueryException: could not resolve property: active of: com.db.tables.PersonTable
what i'm doing wrong?
Base class all entities should inherit these fields
#XmlRootElement
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class BaseTable implements Serializable
{
private static final long serialVersionUID = 1L;
#Column(name = "Updated")
#JsonProperty
#NotNull
protected Timestamp updated;
#Column(name = "Active")
#JsonProperty
#NotNull
protected byte active;
public BaseTable ()
{
active = (byte)1;
updated = DbUtils.getCurrentTimeStamp();
}
public byte getActive()
{
return active;
}
public void setActive(byte active)
{
this.active = active;
}
public Timestamp getUpdated()
{
return updated;
}
public void setUpdated(Timestamp updated)
{
this.updated = updated;
}
#Override
public String toString()
{
return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + active;
result = prime * result + ((updated == null) ? 0 : updated.hashCode());
return result;
}
#Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
BaseTable other = (BaseTable) obj;
if (active != other.active) return false;
if (updated == null)
{
if (other.updated != null) return false;
}
else if (!updated.equals(other.updated)) return false;
return true;
}
}
A class that inherits
#Entity(name = "Persons")
#Table(name = "Persons")
public class PersonTable extends BaseTable implements Serializable
{
private static final long serialVersionUID = -5793514680136648542L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PersonId")
private short personId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="personId")
PortalUserTable portalUser;
//getters&settersand more fields
}
one more class that inherits
#Entity(name = "PortalUser")
#Table(name = "PortalUser")
public class PortalUserTable extends BaseTable implements Serializable
{
private static final long serialVersionUID = -5793514680136648542L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PersonId")
private short personId;
#OneToOne
(mappedBy = "portalUser")
PersonTable person;
//getters&settersand more fields
}
the query
public ObjectDaoResponse getAllTigrisUsers() throws JsonProcessingException
{
try
{
Query q = sessionFactory.getCurrentSession().createQuery("SELECT new com.db.queries.users.User( u.portalUserId ,p.personName) FROM PortalUsers u INNER JOIN u.person p WHERE portalUserId = p.personId AND p.active = 1 AND u.active = 1");
List<TigrisUser> l = q.list();
return ObjectDaoResponse.getAnOkResponse(l);
}
catch(Exception e)
{
System.out.println(e);
return ObjectDaoResponse.getGeneralFailureResponse();
}
}
#MappedSuperclass
public class BaseTable ...
I would suggest to change naming convention Base(Table) -> Base(Entity). Do the same for all entity classes.
You should take care of inheritance strategy - https://en.wikibooks.org/wiki/Java_Persistence/Inheritance

Categories