I have a persistence model like this one :
#Entity
#Table(name="CMM_DT_EMPLOYEE")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "EMP_TYPE")
public abstract class Employee {
#Id
protected Integer employeeId;
...
}
#Entity
#DiscriminatorValue(value = "FULL")
public class FullTimeEmployee extends Employee {
protected Integer salary;
// ...`enter code here`
}
#Entity
#DiscriminatorValue(value = "PART")
public class PartTimeEmployee extends Employee {
protected Float hourlyWage;
}
Named query (select c from FullTimeEmployee c) not working. Its returning only one row although there are many rows for this discriminator type in the Employee Table. Please help.
Related
I'm facing a problem trying to make a JPA repository on an abstract class.
What I'm willing to do is a method that filters, paginates and returnes 3 differents kind of objects in a single list. Some have shared properties (grouped in AbstractClass).
Here are my different classes :
Mother abstract class
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "te_abstract_data")
#DiscriminatorColumn(name="data_type")
public abstract class AbstractData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "data_type")
#Enumerated(EnumType.STRING)
private DataType dataType;
}
AbstractClass
#MappedSuperclass
public class AbstractClass extends AbstractData {
#ManyToOne
#JoinColumn(name = "fk_obj_id")
private ObjEntity opbj;
}
ClassA & ClassB classes
#Entity
#DiscriminatorValue("CLASS_A")
#Table(name = "te_class_a")
#PrimaryKeyJoinColumn(name="fk_data_id")
public class ClassAEntity extends AbstractClass {
// some fields...
}
ClassC
#Entity
#DiscriminatorValue("CLASS_C")
#Table(name = "te_class_c")
#PrimaryKeyJoinColumn(name="fk_data_id")
public class ClassCEntity extends AbstractData {
// some fields...
}
And here is my repository :
#Repository
public interface DataDao extends JpaRepository<AbstractData, Integer> {
#Query(value =
"SELECT ad " +
"FROM AbstractData ad " +
"WHERE ad.obj.name = :objName " +
// some other filters on various fields
"ORDER BY ad.id ASC"
)
List<AbstractData> findFiltered(
Pageable pageable,
String objName
);
}
The current query in my repository ignores only returns ClassB object, even if ClassA and C's objects are well initialized. I have no idea about what could be wrong...
Any idea how I could solve this ?
I am making an application based on JPA/EclipseLink, I implemented a soft delete functionality using #AdditionalCriteria in the root class of the hierarchy of entities (all entities inherit from this).
My problem is that now, I need to create a special entity that contains multiple relationships with other entities; and I need recover all relationed entities, including soft deleted ones. It is possible disabled #AdditionalCriteria only in the relations of this special entity with EclipseLink? If not, what is the best option to do this? My code looks like the following:
////Example of my top entity class (all others inherit from this)
#AdditionalCriteria("this.deleted = false")
public abstract class TopHierarchyClass {
···
#Column(name = "deleted")
protected boolean deleted = false;
···
}
//Example of entity that needs recover all relationed entities including soft deleted
#Entity
#Table(name = "special_entities")
public class SpecialEntity extends EntityBase {
···
#JoinColumn(name = "iditem", referencedColumnName = "id")
#ManyToOne(fetch = FetchType.LAZY)
private Item item;
···
}
#Entity
#Table(name = "items")
public class Item extends EntityBase {
···
}
Thanks in advance
Create a new entity for the same table without the #AdditionalCriteria. This way you can retrieve all records from that table without applying the additional filter.
For example:
public interface Person {
Long getId();
void setId(Long id);
Date getDeletedAt();
void setDeletedAt(Date deletedAt);
}
#MappedSupperclass
public class PersonEntity implements Person {
#Id
private Long id;
private Date deletedAt;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Date getDeletedAt() { return deletedAt; }
public void setDeletedAt(Date deletedAt) { this.deletedAt = deletedAt; }
}
#Entity
#Table(name = "people")
#AdditionalCriteria("this.deletedAt is null")
public class ActivePersonEntity extends PersonEntity {
}
#Entity
#Table(name = "people")
public class RawPersonEntity extends PersonEntity {
}
public class PeopleRepository {
#PersistenceContext
private EntityManager em;
public List<Person> all() {
return all(false);
}
public List<Person> all(boolean includeSoftDeleted) {
if (!includeSoftDeleted) {
return em.createQuery("select p from ActivePersonEntity p", ActivePersonEntity.class).getResultList();
} else {
return em.createQuery("select p from RawPersonEntity p", RawPersonEntity.class).getResultList();
}
}
}
Also, if your #AdditionalCriteria is in a super class, you may override it by declaring a new empty #AdditionalCriteria in a sub class:
You can define additional criteria on entities or mapped superclass.
When specified at the mapped superclass level, the additional criteria
definition applies to all inheriting entities, unless those entities
define their own additional criteria, in which case those defined for
the mapped superclass are ignored.
#AdditionalCriteria doc
I'm getting Unknown column 'imageprope1_.enid' in 'field list' with the following mapping:
#OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name="enid", referencedColumnName="pnid")
private List<EntityImageProperty> imageProperties = new ArrayList<>();
Here's the key entity mapping:
BaseEntityProperty
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="enpptpcd", discriminatorType=DiscriminatorType.STRING)
#Table(name=BaseEntityProperty.TABLE_NAME)
public abstract class BaseEntityProperty implements Serializable {
#Id
#Column(name="enppid")
private String entityPropertyId=null;
#Column(name="enid")
private String entityId=null;
EntityImageProperty
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorValue(EntityImageProperty.DISCRIMINATOR_VALUE)
#Table(name=EntityImageProperty.TABLE_NAME)
#PrimaryKeyJoinColumn(name="enppid")
public class EntityImageProperty extends BaseEntityProperty {
It looks like #JoinColumn(name="enid", referencedColumnName="pnid") tells Hibernate to join on EntityImageProperty.enid, whereas it should join on BaseEntityProperty.enid.
How can I extend an entity with another entity but both of them referring to the same table ? Is it possible ? The structure is something like this :
#Entity
#Table(name = "users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable{
private int id;
private String name;
}
#Entity
#Table(name = "users")
#NamedQuery(name="SubUser.findAll", query="SELECT su FROM SubUser su")
public class SubUser extends User {
#Override
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return super.getId();
}
//- Other fields and getter setter
}
I tried this way Extend JPA entity to add attributes and logic
but I got this exception
org.hibernate.mapping.SingleTableSubclass cannot be cast to org.hibernate.mapping.RootClass
Update 1
I already put the #Id for the SubUser because the #Entity shows this exception
The entity has no primary key attribute defined
Add the #Inheritance annotation to the super class
Implement Serializable
Add a getter for id (you don't need a setter necessarily)
id should be Integer, not int, so that you can represent unassigned ids with null.
Code:
#Entity
#Table(name = "users")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
public class SubUser extends User {
}
Any basic JPA docs would describe inheritance, discriminators and use of #Id.
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="DISCRIM", discriminatorType=DiscriminatorType.STRING)
#DiscriminatorValue("User")
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
}
#Entity
#DiscriminatorValue("SubUser")
#NamedQuery(name="SubUser.findAll", query="SELECT su FROM SubUser su")
public class SubUser extends User {
}
I have have two classes that inherit from an abstract class and have a parent-children relation.
So I use annotation OneToMany and ManyToOne but the parent entity in child class is always null.
Can Someone help me please, I have spend several hours to googling and test many conf without success.
These are code from my classes :
public #Table(name="flowentity") #Entity abstract class FlowEntity {
final static Logger log = LoggerFactory.getLogger(FlowEntity.class);
//Globals informations concerning the flow state
private #Id #GeneratedValue(strategy = GenerationType.IDENTITY) Integer flowId = 0;
private String flowName;
private #OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
Set<PeopleEntity> actorSet = new HashSet<>();
//Global parameters for most of flows
//Organizational parameters
private #OneToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name="organisationalEntity_Id")
OrganisationalEntity organisationalEntity;
...
public #Table(name="ams_newCPEntity") #Entity class NewMultiCPEntity extends FlowEntity {
private #OneToMany(targetEntity=NewCPEntity.class, fetch=FetchType.EAGER, cascade=CascadeType.ALL,mappedBy="parent")
Set<NewCPEntity> cpList = new HashSet<NewCPEntity>();
//Constructor
public NewMultiCPEntity(){
setFlowName(EnumFlow.N_CP_M.getFlowAcronym());
}
...
public #Table(name="ams_newCPEntity") #Entity class NewCPEntity extends FlowEntity {
final static Logger log = LoggerFactory.getLogger(NewCPEntity.class);
private boolean formNCPValidated;
private #ManyToOne #JoinColumn(name="parent_Id", nullable=false)
NewMultiCPEntity parent;
public NewCPEntity(){
log.debug("Instanciation of a new CP");
setFlowName(EnumFlow.N_CP.getFlowAcronym());
}
public #Override OrganisationalEntity getOrganisationalEntity(){
return parent.getOrganisationalEntity();
}
...
If I don't add the #JoinColumn annotation, JPA create an association table but is not able to retrieve the parent whereas the association can be done directly by requesting in database.
Thankyou very much to help.
Regards,
Thank you Chris for your comment, you are right, I forget to change the name of the table. I don't think it was the problem because the inheritance mapping is in one table flowentity with a DTYPE discriminator column.
Finally I resolve my problem by setting parent attributs when adding a new child like this :
public #Table #Entity class NewMultiCPEntity extends FlowEntity {
private #OneToMany(targetEntity=NewCPEntity.class, fetch=FetchType.EAGER, cascade=CascadeType.ALL)
List<NewCPEntity> cpList = new ArrayList<>();
//Constructor
public NewMultiCPEntity(){
setOrganisationalEntity(new OrganisationalEntity());
setFlowName(EnumFlow.N_CP_M.getFlowAcronym());
}
public List<NewCPEntity> getNCPList(){
if(cpList == null){
cpList = new ArrayList<>();
}
if(cpList.isEmpty()){
addCPEntity(new NewCPEntity());
}
return Collections.unmodifiableList(cpList);}
public boolean removeCPEntity(NewCPEntity entity){
return cpList.remove(entity);
}
public boolean addCPEntity(NewCPEntity entity){
entity.setParent(this);
entity.setOrganisationalEntity(this.getOrganisationalEntity());
return cpList.add(entity);
}
And I remove the override of getOrganizationalEntity in the child :
public #Table #Entity class NewCPEntity extends FlowEntity {
final static Logger log = LoggerFactory.getLogger(NewCPEntity.class);
private #ManyToOne(targetEntity=NewMultiCPEntity.class,cascade=CascadeType.ALL)
NewMultiCPEntity parent;
public NewCPEntity(){
log.debug("Instanciation of a new CP");
setFlowName(EnumFlow.N_CP.getFlowAcronym());
}
public NewMultiCPEntity getParent() {
return parent;
}
public void setParent(NewMultiCPEntity parent){
this.parent = parent;
}
Regards,