#Entity
#Table(name = "parent");
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Parent {
#Id
#SequenceGenerator(name = "ME_SEQ", sequenceName = "ME_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ME_SEQ")
#Column(name = "PARENT_ID", columnDefinition = "NUMBER(38,0)", nullable = false, unique = true)
private Long id;
}
There is also a child entity (seperate table) which has a PK and FK that points to Parent ID.
#Entity
#Table(name = "child")
public class Child extends Parent {
#Id
#Column(name = "PARENT_ID")
private Long id;
}
Even though there is two separated tables, I get an error from Hibernate:
org.hibernate.mapping.UnionSubclass cannot be cast to
org.hibernate.mapping.RootClass
Is it not possible to have ID in the child class, even if it's a different table from the parent?
Related
I've these tables in my Oracle database (which I can't change):
Table_A
Table_B
Table_AB
ID (PK)
ID_B (PK)
ID_A (PK)
COMMON_ID (PK)
COMMON_ID (PK)
B_ID (PK)
...
...
COMMON_ID (PK)
Tables A and B have a many-to-many relationship and Table AB contains two foreign keys:
FK_1: ID_A, COMMON_ID referencing table A (ID, COMMON_ID)
FK_2: B_ID, COMMON_ID referencing table B (ID_B, COMMON_ID)
I tried to map these table but I have a problem in my jointable due the fact column "COMMON_ID" is shared between FK_1 e FK_2. Hibernate in fact tries to create the jointable with two column with the same name, generating this exception:
org.hibernate.MappingException: Repeated column mapping for collection: B.collectionA column: COMMON_ID
These are my entities, please can anyone help me to solve the problem? Thank you in advance!
Entity A:
#Entity
#Table(name = "Table_A")
#IdClass(value = A_PK.class)
public class A implements Serializable {
private static final long serialVersionUID = 2210864155927195752L;
#Id
#SequenceGenerator(name = "TABLE_A_SEQ", sequenceName = "TABLE_A_PKSEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TABLE_A_SEQ")
private long id;
#Id
#Column(name="COMMON_ID")
private Integer commonId;
#ManyToMany
#JoinTable(name = "TABLE_AB",
joinColumns = {
#JoinColumn(name = "ID_A", referencedColumnName = "ID"),
#JoinColumn(name = "COMMON_ID", referencedColumnName = "COMMON_ID")
},
inverseJoinColumns = {
#JoinColumn(name = "B_ID", referencedColumnName = "ID_B"),
#JoinColumn(name = "COMMON_ID", referencedColumnName = "COMMON_ID")
}
)
#LazyCollection(LazyCollectionOption.FALSE)
private List<B> collectionB;
getter, setter, hashcode, equals
Entity A_PK:
public class A_PK implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private Integer commonId;
getter, setter, hashcode, equals
Entity B:
#Entity
#Table(name="TABLE_B")
#IdClass(value = B_PK.class)
public class B implements Serializable {
private static final long serialVersionUID = -5761968943282358603L;
#Id
#Column(name = "ID_B", unique = true, nullable = false)
#SequenceGenerator(name = "TABLE_B_SEQ", sequenceName = "TABLE_B_PKSEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TABLE_B_SEQ")
private Long id;
#Id
#Column(name="COMMON_ID")
private Integer commonId;
#ManyToMany(mappedBy = "collectionB")
private List<A> collectionA;
getter, setter, hashcode, equals
Entity B_PK:
public class B_PK implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Integer commonId;
getter, setter, hashcode, equals
I am trying to save data in two table using OneToOne mapping.I have followed
this,this,this,this and few more online resources to accomplish this, but it is throwing
ORA-02291: integrity constraint (TableName.TEST_ID) violated - parent key not found
Creating a table where column TESTID is foreign key. In the parent table TESTID is primary key.That primary key is generated using sequence generator
CREATE TABLE EW_TEST_REFTABLE (
ID int NOT NULL PRIMARY KEY,
TESTNAME VARCHAR2(20) NOT NULL,
TESTID int,
CONSTRAINT test_id FOREIGN KEY(TESTID)
REFERENCES EW_TESTDATA(TESTID)
);
Ew_testdataEntity.java (Entity class of parent table)
#Entity
#Table(name = "EW_TESTDATA")
public class Ew_testdata {
#Id
#SequenceGenerator(name = "sube_seq",
sequenceName = "EW_TESTDATA_SEQ",
allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sube_seq")
#Column(name = "TESTID")
private int testid;
#Column(name = "TESTNAME")
private String testname;
// Ew_test_reftable is another entity class.In that table the column
// TESTID (foreign key) must be same as the primary key of this
// entity/table(EW_TESTDATA)
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "TESTID",unique = true)
private Ew_test_reftable ewtestreftable;
//Constructor
// getter & setter
}
Ew_test_reftable.java
#Entity
#Table(name = "EW_TEST_REFTABLE")
public class Ew_test_reftable {
#Id
#SequenceGenerator(name = "subf_seq", sequenceName = "EW_REF_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "subf_seq")
#Column(name = "ID")
private int id;
#Column(name = "TESTNAME")
private String testname;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
//Constructor,getter & setter
}
Service to save data using Jpa
#Override
public Ew_testdata ew_testdata(String name) {
Ew_test_reftable ew_test_reftable = new Ew_test_reftable();
ew_test_reftable.setTestname("test");
Ew_testdata ew_testdata = new Ew_testdata();
ew_testdata.setTestname(name);
ew_testdata.setEwtestreftable(ew_test_reftable);
iew_tEst.ewTestdata(ew_testdata);
return null;
}
The problem seems to be similar to few other problem described in SO but still i am not able to figure out where I am making mistake
Your entity and table structure looks opposite, and that making so much confusion to understand.
Now, referring to exception
ORA-02291: integrity constraint (TableName.TEST_ID) violated - parent key not found
This mean, you don't have reference of parent id in child table when adding new row to child table.
In Ew_test_reftable class, you have
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
If I understand correctly, testid is your foreign key in EW_TEST_REFTABLE, then why are you using GenerationType.IDENTITY ? This will create new sequence id and may not match with parent key and result in error/exception.
As per my understanding of your design,
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
change to
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "TESTID",unique = true)
private Ew_testdata ew_testdata;
And similar to above code should be removed from Ew_testdata entity (There might be slight change here and there)
Ive added 2 hibernate model objects
First table
#Entity
#Table(name = "ACTIVITIES")
public class ActivityMO extends ModelBase {
#Column(name = "CA_ID", nullable = false, insertable = true,updatable = true, length = 22, precision = 0)
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "G1")
#SequenceGenerator(name = "G1", sequenceName = "CSM_ACTIVITIES_SEQ")
private Long id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "activityId", cascade = {CascadeType.ALL})
#Fetch(FetchMode.JOIN)
List<ActivitiesProductsMO> relatedProducts;
...getters / setters
}
The other table is
#Entity
#Table(name = "ACTIVITIES_PRODUCTS")
public class ActivitiesProductsMO {
#Column(name = "CAP_ID")
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "G1")
#SequenceGenerator(name = "G1", sequenceName = "ACTIVITIES_PRODUCTS_SEQ")
private Long id;
#Column(name = "CAP_ACTIVITY_ID")
private Long activityId;
#Column(name = "CAP_PRODUCT_ID")
private Long productId;
...getters/setters
}
The point is to populate each db record for ActivitiesProductsMO.activityId with ActivityMO.id value
I.e.
If I create an activity record with id = 555
I'll get another activity_product record with activityId of 555
How can i get this to work?
Thank you!
Instead of manually trying to map the entitiy relations with long values you should use a bidirectional OneToMany relationship from ActivityMO to ActivitiesProductsMO
change ActivitiesProductsMO to:
#Entity
#Table(name = "ACTIVITIES_PRODUCTS")
public class ActivitiesProductsMO {
// cut unimportant code ...
#ManyToOne
#JoinColumn(name = "CAP_ACTIVITY_ID")
private ActivityMO activityId;
// cut unimportant code ...
}
If you then were to persist an ActivityMO that already has ActivitiesProductsMO entries in its relatedProducts List, the Cascade type should actually take care and create those products while filling out the CAP_ACTIVITY_ID database field with the right value.
Another Possible Solution:
Use a Unidirectional OneToMany:
#Entity
#Table(name = "ACTIVITIES")
public class ActivityMO extends ModelBase {
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
#Fetch(FetchMode.JOIN)
#JoinColumn(name = "CAP_ACTIVITY_ID")
List<ActivitiesProductsMO> relatedProducts;
}
And remove the
private Long activityId;
from your ActivitiesProductsMO class.
This should both lead to identical database structure. But in the second case you would no longer have the "backlink" inside java from ActivitiesProductsMO to ActivityMO
When JPA tries to select AdmUser entity I have sql error:
ERROR: column locations1_.name does not exist.
Is there anything wrong with my entities? My AdmUser entity:
#Entity
#Table(name = "ADM_USERS")
#SequenceGenerator(name = "ADM_USER_SEQ", sequenceName = "ADM_USER_SEQ", allocationSize = 1)
public class AdmUser implements EntityInt, Serializable {
private static final long serialVersionUID = 786L;
#Id
#Column(nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ADM_USER_SEQ")
private Long id;
(...)
#ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
#JoinTable(name = "loc_locations_adm_users", joinColumns = #JoinColumn(name = "id_user", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name = "id_location"))
#OrderBy("name")
private Set<LocLocation> locations;
(...)
}
My LocLocation Entity:
#Entity
#Table(name = "loc_locations", schema = "public")
#SequenceGenerator(name = "LOC_LOCATIONS_SEQ", sequenceName = "LOC_LOCATIONS_SEQ", allocationSize = 1)
public class LocLocation implements EntityInt, java.io.Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "LOC_LOCATIONS_SEQ")
private Long id;
#Column(nullable = false, unique = true, length = 200)
private String name;
(...)
#ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY, mappedBy="locations")
private List<AdmUser> users;
}
And now - when JPA tries to select AdmUser entity I have sql error. The query generated by JPA looks that:
select
admuser0_.id as id1_2_0_,
admuser0_.actived as actived2_2_0_,
admuser0_.admin as admin3_2_0_,
admuser0_.allow_ip as allow_ip4_2_0_,
admuser0_.created as created5_2_0_,
admuser0_.deleted as deleted6_2_0_,
admuser0_.id_domain as id_doma16_2_0_,
admuser0_.email as email7_2_0_,
admuser0_.language as language8_2_0_,
admuser0_.login as login9_2_0_,
admuser0_.name as name10_2_0_,
admuser0_.passwd as passwd11_2_0_,
admuser0_.phone as phone12_2_0_,
admuser0_.picture as picture13_2_0_,
admuser0_.surname as surname14_2_0_,
admuser0_.theme as theme15_2_0_,
locations1_.id_user as id_user1_2_1_,
loclocatio2_.id as id_locat2_6_1_,
loclocatio2_.id as id1_17_2_,
loclocatio2_.description as descript2_17_2_,
loclocatio2_.name as name3_17_2_
from
public.ADM_USERS admuser0_
left outer join
public.loc_locations_adm_users locations1_
on admuser0_.id=locations1_.id_user
left outer join
public.loc_locations loclocatio2_
on locations1_.id_location=loclocatio2_.id
where
admuser0_.id=1
order by
locations1_.name
The order by points to locations1_.name, but should be loclocatio2_.name. Have I anything wrong with my entities?
You have a Set on one side for that field. Consequently there is no "ordering" (other than what hashCode() gves). Use a List if you want ordering (this is Java, nothing to do with JPA really).
You also seem to be missing a "mappedBy" on the non-owner side of that M-N.
The #OrderBy works fine with ManyToMany. Also with the structure I provided in my question. The problem was my query and JPA didn't managed with it. Sorry.
I have hierarchy of classes, for example AbstractClass - Employee - Engineer (and many others subclasses), and I use single table per class hierarchy strategy.
AbstractClass has property case, in Employee I define #DiscriminatorFormula("case"), Engineer has some #DiscriminatorValue.
When I load all objects with HQL-query SELECT id FROM Employee, Hibernate makes this SQL-query:
select employee0_.id as col_0_0_ from public.tbl_employee employee0_ where employee0_.case in ('engineer', 'operator')
In other words, Hibernate adds redundant restrictoin with all discriminator values.
Is there a way to exclude this IN restriction from SQL?
There is some simplified mapping of AbstractClass and Employee:
#MappedSuperclass
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class AbstractClass {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GEN")
#SequenceGenerator(name = "SEQ_GEN", sequenceName = "objectid_sequence", allocationSize = 100)
private long id;
#Column(name = "case", nullable = false)
private String case;
}
#Entity
#Table(name = "tbl_employee")
#DiscriminatorFormula("case")
public class Employee extends AbstractClass {
#Column(name = "name", nullable = false)
private String name = "";
}