I try to persist one parent entity which is joined with another child entity, but the problem is that the id is not generated for this child when persisting so I have this error : [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] ORA-01400: cannot insert NULL into ("L2S$OWNER"."SABRI"."TRANSITION_MATRIX_ID")
there is the child Entity :
#Data
#Entity
#IdClass(MyLibrarySabriEntityPK.class)
#Table(name = "SABRI", schema = "L2S$OWNER", catalog = "")
public class MyLibrarySabriEntity extends ActionForm {
#Access(AccessType.FIELD)
#Id
#ManyToOne
#JoinColumn(name = "TRANSITION_MATRIX_ID", referencedColumnName = "ID_TRANSITION_MATRIX")
private MyLibraryTestEntity sabriEntity;
#Id
private String RATING_ID_ROW;
#Id
private String RATING_ID_COL;
#Basic
#Column(name = "TRANSITION_PROBABILITY", nullable = true, insertable = true, updatable = true, precision = 20)
private Double TRANSITION_PROBABILITY;}
the PK class :
#Data
public class MyLibrarySabriEntityPK implements Serializable {
private String TRANSITION_MATRIX_ID;
private String RATING_ID_ROW;
private String RATING_ID_COL;
public MyLibrarySabriEntityPK(String TRANSITION_MATRIX_ID,String RATING_ID_COL,String RATING_ID_ROW ){
this.TRANSITION_MATRIX_ID=TRANSITION_MATRIX_ID;
this.RATING_ID_COL = RATING_ID_COL;
this.RATING_ID_ROW= RATING_ID_ROW;
}
}
there is the parent Entity:
#Data
#Entity
#Table(name = "TEST", schema = "L2S$OWNER", catalog = "")
public class MyLibraryTestEntity extends ActionForm {
#Access(AccessType.FIELD)
#OneToMany(mappedBy = "sabriEntity", cascade = CascadeType.PERSIST)
private final List<MyLibrarySabriEntity> entities = new ArrayList<MyLibrarySabriEntity>(25);
public void addEntitysabri(MyLibrarySabriEntity entity) {
getEntities().add(entity);
entity.setSabriEntity(this);
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "IdGenerated")
#GenericGenerator(name = "IdGenerated", strategy = "dao.Identifier")
#Column(name = "ID_TRANSITION_MATRIX", nullable = false, insertable = false, updatable = false, length = 10)
private String ID_TRANSITION_MATRIX;
#Basic
#Column(name = "REFERENCE", nullable = true, insertable = true, updatable = true, precision = 0)
private Integer reference;}
And here I try to persist the parent table which is supposed to persist also the child table but the Id is not generated !
MyLibrarySabriEntity Entity = null;
MyLibraryTestEntity test = getMyLibraryTestEntity(matrixStartDate, matrixName); // here I get the values of my entity test (parent)
try {
transaction.begin();
for (int row = 0; row < 20; row++) {
for (int col = 0; col < 20; col++) {
double val = cells.get(row + FIRST_ROW, col + FIRST_COL).getDoubleValue();
Entity = getMyLibrarySabriEntity(col, row, val); // this get the values of the Entity parameters (child)
Entity.setSabriEntity(test);
test.addEntitysabri(Entity);
em.persist(test);
}
}
} catch (Exception e) {
if (transaction.isActive())
transaction.rollback();
LOGGER.warn(e.getMessage(), e);
} finally {
if (transaction.isActive())
transaction.commit();
em.close();
}
Assuming you are using JPA 2.0+
Remove this mapping completely:
#Id
#Column(name = "TRANSITION_MATRIX_ID", nullable = false,
insertable = true, updatable = true, length = 100)
private String TRANSITION_MATRIX_ID;
and put the #Id directly on the ManyToOne and remove the insertable and updateable attributes.
#Access(AccessType.FIELD)
#Id
#ManyToOne
#JoinColumn(name = "TRANSITION_MATRIX_ID", referencedColumnName = "ID_TRANSITION_MATRIX")
private MyLibraryTestEntity sabriEntity;
Update your ID class accordingly. Any previous reference to TRANSITION_MATRIX_ID should be replaced with a reference to sabriEntity. You are also confusing #EmbeddedId and #IdClass: Only the former would contain column definitions whereas you are using the latter approach.
public class MyLibrarySabriEntityPK implements Serializable {
private String sabriEntity;
private String RATING_ID_ROW;
private String RATING_ID_COL;
}
See:
https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#JPA_2.0
Thank's to Alan Hay, I found the problem , I change the property TRANSITION_MATRIX_ID of my IDclass to sabriEntity and I delete all the annotation of this class !
Child entity
#Data
#Entity
#IdClass(MyLibrarySabriEntityPK.class)
#Table(name = "SABRI", schema = "L2S$OWNER", catalog = "")
public class MyLibrarySabriEntity extends ActionForm {
#Access(AccessType.FIELD)
#ManyToOne
#Id
#JoinColumn(name = "TRANSITION_MATRIX_ID", referencedColumnName = "ID_TRANSITION_MATRIX")
private MyLibraryTestEntity sabriEntity;
#Id
private String RATING_ID_ROW;
#Id
private String RATING_ID_COL;
#Basic
#Column(name = "TRANSITION_PROBABILITY", nullable = true, insertable = true, updatable = true, precision = 20)
private Double TRANSITION_PROBABILITY;
Parent Entity
#Data
#Entity
#Table(name = "TEST", schema = "L2S$OWNER", catalog = "")
public class MyLibraryTestEntity extends ActionForm {
#Access(AccessType.FIELD)
#OneToMany(mappedBy = "sabriEntity", cascade = CascadeType.PERSIST)
private final List<MyLibrarySabriEntity> entities = new ArrayList<MyLibrarySabriEntity>(25);
public void addEntitysabri(MyLibrarySabriEntity entity) {
getEntities().add(entity);
entity.setSabriEntity(this);
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "IdGenerated")
#GenericGenerator(name = "IdGenerated", strategy = "dao.Identifier")
#Column(name = "ID_TRANSITION_MATRIX", nullable = false, insertable = false, updatable = false, length = 10)
private String ID_TRANSITION_MATRIX;
#Basic
#Column(name = "REFERENCE", nullable = true, insertable = true, updatable = true, precision = 0)
private Integer reference;
PK Class
#Data
public class MyLibrarySabriEntityPK implements Serializable {
private MyLibraryTestEntity sabriEntity;
private String RATING_ID_ROW;
private String RATING_ID_COL;
public MyLibrarySabriEntityPK() {
}
public MyLibrarySabriEntityPK(MyLibraryTestEntity sabriEntity,String RATING_ID_COL,String RATING_ID_ROW ){
this.sabriEntity=sabriEntity;
this.RATING_ID_COL = RATING_ID_COL;
this.RATING_ID_ROW= RATING_ID_ROW;
}
}
Related
OneToOne mapping not working: EntityA.entityB referencing EntityB not mapped to a single property
I have two entities, EntityA and EntityB.
EntityA has a composite primary key on two fields: id and flag.
EntityB also has a composite primary key on two fields: id and flag.
The two entities are linked with a common field / column: entityBKey. (This is a foreign key but not explicitly defined as such at the database level, if that makes a difference. Old design can't really change much)
This is how I am calling EntityA:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<EntityA> criteriaQuery = builder.createQuery(EntityA.class);
Root<EntityA> from = criteriaQuery.from(EntityA.class);
criteriaQuery.select(from);
But I get this error on application boot:
EntityA.entityB referencing EntityB not mapped to a single property
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:203)
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:104)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1750)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1694)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1623)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:295)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:86)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:479)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:709)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:746)
In some places I have read it says that non-primary keys can be referenced by using the referencedColumnName attribute but it is clearly not working.
Any ideas what I can do here? Much appreciated.
EntityA:
#Entity
#Table(name = "EntityA")
#IdClass(KeyClass.class)
public class EntityA implements Serializable {
#Id
#Column(name = "id", nullable = false)
protected Integer id = null;
#Id
#Column(name = "flag", nullable = false)
protected Integer flag = null;
#Column(name = "EntityAKey", nullable = false)
private String entityAKey = null;
#Column(name = "EntityBKey", nullable = false)
private String entityBKey = null;
#OneToOne(mappedBy="entityA")
private EntityB entityB;
public EntityA() {
super();
}
}
EntityB:
#Entity
#Table(name = "EntityB")
#IdClass(KeyClass.class)
public class EntityB implements Serializable {
#Id
#Column(name = "id", nullable = false)
protected Integer id = null;
#Id
#Column(name = "flag", nullable = false)
protected Integer flag = null;
#Column(name = "EntityBKey", nullable = false)
private String entityBKey = null;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "entityBKey", referencedColumnName = "entityBKey", insertable = false, updatable = false),
#JoinColumn(name = "flag", referencedColumnName = "flag", insertable = false, updatable = false)}
)
#Where(clause = "flag=1")
private EntityA entityA;
public EntityB() {
super();
}
}
KeyClass:
public class KeyClass implements Serializable {
private Integer id = null;
private Integer flag = null;
public KeyClass() {
}
public KeyClass(Integer id, Integer flag) {
this.id = id;
this.flag = flag;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getFlag() {
return flag;
}
public void setFlag(Integer flag) {
this.flag = flag;
}
#Override
public boolean equals(Object o) {
...
}
#Override
public int hashCode() {
...
}
}
When I run this code, it is running with out error. But When I check the values, as you can see, In the "Tbl_InstructorDetail" table the parentId is null
can anyone help.
thank you.
This is my Entities and my main class with table relation
enter image description here
this is my tables from my database
create table Tbl_Instructor
(
uuid int identity
constraint Pk_Tbl_Instructor_uuid
primary key,
Title nvarchar(50)
)
create table Tbl_InstructorDetail
(
uuid int identity
constraint Pk_Tbl_InstructorDetail_uuid
primary key,
Created_By nvarchar(50),
parentId int
constraint Fk_Tbl_InstructorDetail_Tbl_Instructor
references Tbl_Instructor
)
#Entity
#Table(name = "Tbl_InstructorDetail", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorDetailEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Created_By", nullable = true, length = 50)
private String createdBy;
#Basic
#Column(name = "parentId", nullable = true,insertable = false,updatable = false)
private Integer parentId;
#OneToOne
#JoinColumn(name = "parentId",referencedColumnName="uuid")
private TblInstructorEntity instructorEntity;
#Entity
#Table(name = "Tbl_Instructor", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Title", nullable = true, length = 50)
private String title;
#OneToOne(mappedBy="instructorEntity",cascade = CascadeType.ALL)
private TblInstructorDetailEntity detailEntity;
Main class
TblInstructorEntity instructor = new TblInstructorEntity();
instructor.setTitle("This is a Test");
TblInstructorDetailEntity detail = new TblInstructorDetailEntity();
detail.setCreatedBy("Kyle");
instructor.setDetailEntity(detail);
session.getTransaction().begin();
session.save(instructor);
session.getTransaction().commit();
You don't need to add parentId in TblInstructorDetailEntity because it's referenced from TblInstructorEntity. In main class foreign key pass null because you can take a reference to the parent table before save parent table.
Here down is modified code:
Entity
#Entity
#Table(name = "Tbl_InstructorDetail", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorDetailEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Created_By", nullable = true, length = 50)
private String createdBy;
// remove parentId column because it is foreign key
#OneToOne
#JoinColumn(name = "parentId",referencedColumnName="uuid")
private TblInstructorEntity instructorEntity;
// getter setter
}
#Entity
#Table(name = "Tbl_Instructor", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Title", nullable = true, length = 50)
private String title;
#OneToOne(mappedBy="instructorEntity",cascade = CascadeType.ALL)
private TblInstructorDetailEntity detailEntity;
// getter setter
}
Main
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
TblInstructorEntity instructor = new TblInstructorEntity();
instructor.setTitle("This is a Test");
TblInstructorDetailEntity detail = new TblInstructorDetailEntity();
detail.setCreatedBy("Kyle");
session.save(instructor); // Save parent entity
detail.setInstructorEntity(instructor); // Reference from parent entity
session.save(detail); // Save child entity
session.getTransaction().commit();
HibernateUtil.shutdown();
I have the following code for many to many or many to one relationship persistence using Spring JPA.
This is my repository test https://github.com/Truebu/testJpa.git
This class has three one-to-many relationships, but none work well
#Entity(name = "routine_assignament")
#Table(name = "routine_assignament")
public class RoutineAssignament {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#Column(name = "date_start",nullable = true,columnDefinition = "DATE")
private Date date_start = new Date();
#Column(name = "date_end",nullable = true,columnDefinition = "DATE")
private Date date_end;
#ManyToOne
#JoinColumn(name = "id_user")
private User user;
#ManyToOne
#JoinColumn(name = "id_routine")
private Routine routine;
#OneToMany(mappedBy = "routine_assignament")
private Set<Score> scores = new HashSet<>();
#OneToMany(mappedBy = "routine_assignament")
private Set<Statistic> statistics = new HashSet<>();
#OneToMany(mappedBy = "routine_assignament")
private Set<KeepRoutine> keepRoutines = new HashSet<>();
The other classes
#Entity(name = "score")
#Table(name = "score")
public class Score {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#Column(name = "commentary",nullable = false,columnDefinition = "TEXT", unique = true)
private String commentary;
#Column(name = "assessment",nullable = false,columnDefinition = "INT", unique = true)
private String assessment;
#ManyToOne
#JoinColumn(name = "id_routine_assignament")
private RoutineAssignament routineAssignament;
}
#Entity(name = "statistic")
#Table(name = "statistic")
public class Statistic {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#Column(name = "time",nullable = false,columnDefinition = "TEXT", unique = true)
private String time;
#ManyToOne
#JoinColumn(name = "id_routine_assignament")
private RoutineAssignament routineAssignament;
}
and
#Entity(name = "keep_routine")
#Table(name = "keep_routine")
public class KeepRoutine {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#ManyToOne
#JoinColumn(name = "id_routine_assignament")
private RoutineAssignament routineAssignament;
}
The entity relationship diagram is this:
My mistake is that it doesn't detect these relationships correctly.
When I run it it generates this:
Failed to initialize JPA EntityManagerFactory: mappedBy reference an unknown target entity property: com.example.demo.model.entities.KeepRoutine.routine_assignament in com.example.demo.model.entities.RoutineAssignament.keepRoutines
This error is reproduced with all three classes (KeepRoutine, Statistic and Score), I don't know why
Your OneToMany mapping is not appropriate. You need to use routineAssignament the property name instead of the table name routine_assignament as shown below. This property name is defined in the ManyToOne relationship.
#OneToMany(mappedBy = "routineAssignament")
private Set<Score> scores = new HashSet<>();
#OneToMany(mappedBy = "routineAssignament")
private Set<Statistic> statistics = new HashSet<>();
#OneToMany(mappedBy = "routineAssignament")
private Set<KeepRoutine> keepRoutines = new HashSet<>();
The "TypeMismatchException: Provided id of the wrong type" error thrown when tried to merge detached entity. It works if the object wasn't detached. It also works if ids aren't #EmbeddedId.
A sample repo can be found here https://github.com/joes-code/hibernate-map
// Asset.java
#Entity
#Table(name = "asset")
public class Asset {
#EmbeddedId
private AssetId id;
#Column(name = "asset_cost"
private BigDecimal price;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "asset_id", referencedColumnName = "asset_id", nullable = false, insertable = false, updatable = false, foreignKey = #ForeignKey(ConstraintMode.NO_CONSTRAINT))
private AssetDetail assetDetail;
}
// AssetId.java
#Embeddable
public class AssetId {
#Column(name = "asset_id", nullable = false)
private Integer assetId;
}
// AssetDetail.java
#Entity
#Table(name = "asset_detail")
public class AssetDetail {
#EmbeddedId
private AssetDetailId id;
#Column(name = "description", length = 35)
private String description;
}
// AssetDetailId.java
#Embeddable
public class AssetDetailId {
#Column(name = "asset_id", nullable = false)
private Integer assetId;
}
I'm using Hibernate 5.4.3.Final
Any ideas what I did wrong? It seems that Hibernate is assuming Asset and AssetDetail share the same Id class?
Well i have this problem
These are my tables
this is my code for "Compra"
#Entity
#Table(name = "compra")
public class Compra implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "codigo", unique = true, nullable = false)
private int codigo;
#ManyToOne
#JoinColumn(name = "codProveedor", nullable = false)
private Proveedor proveedor;
#Column(name = "tipoComprobante", nullable = false)
private String tipoComprobante;
#Temporal(TemporalType.DATE)
#Column(name = "fechaFactura", nullable = false)
private Date fechaFactura;
#Temporal(TemporalType.DATE)
#Column(name = "fechaLlegada", nullable = false)
private Date fechaLlegada;
#Column(name = "serie", nullable = false)
private String serie;
#Column(name = "numero", nullable = false)
private int numero;
#Column(name = "importe", nullable = false)
private double importe;
#Column(name = "vigencia", nullable = false)
private boolean vigencia = true;
#ElementCollection
private List<DetalleCompra> lstDetalle = new ArrayList<DetalleCompra>();
// getters and setters ...
And this is my code for "DetalleCompra"
#Entity
#Table(name = "detalleCompra")
public class DetalleCompra implements Serializable {
#Id
#GeneratedValue(generator = "gen")
#GenericGenerator(name = "gen", strategy = "foreign", parameters = #Parameter(name = "property", value = "compra"))
#Column(name = "codCompra", nullable = false)
private int codCompra;
#ManyToOne
#JoinColumn(name = "codPresentacion", nullable = false)
private Presentacion presentacion;
#Column(name = "imei", nullable = false)
private String imei;
#Column(name = "simcard", nullable = false)
private String simcard;
getters and setters ...
Well everything looks fine, but when i want to save i have this problem
org.hibernate.TransientObjectException: object references an unsaved transient instance – save the transient instance before flushing: DetalleCompra
well it is clear because when i want to save Compra and DetalleCompra, the second table expect the fk value
public void registrar(Compra compra) {
try {
session = HibernateUtil.getSessionFactory().openSession();
trans = session.beginTransaction();
session.save(compra);
trans.commit();
} catch (Exception e) {
trans.rollback();
throw e;
} finally {
session.close();
}
}
Well the pk of table "compra" is generated well but for the other table does not recognized this value autogenerated, why?, how can i solve that?
#ElementCollection
Defines a collection of instances of a basic type or embeddable class.
Must be specified if the collection is to be mapped by means of a
collection table.
You use wrong annotation to represent relation. There is one to many relation between Compra and DetalleCompra.
You should change #ElementCollection annotation to #OneToMany. Do not forget to specify join columns #JoinColumn(name="codCompra"). I assume that Presentacion is properly mapped.
See also
Unidirectional Mapping vs. Bidirectional Mapping
mappedBy attribute
#OneToMany annotation
#ElementCollection annotation