Open JPA Saving OneToMany , foreign key not set - java

I've two tables: TaStock and TaStockPrice. Field tastockid in table TaStockPrice is the foreign key to table TaStock.
#Entity
public class TaStock {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id
#OneToMany(mappedBy = "taStock", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<TaStockPrice> tastockpriceList;
public void addTaStockPrice(TaStockPrice taStockPrice) {
if (taStockPrice == null) {
return;
}
taStockPrice.setTaStock(this);
if (tastockpriceList == null) {
tastockpriceList = new ArrayList<TaStockPrice>();
tastockpriceList.add(taStockPrice);
} else if (!tastockpriceList.contains(taStockPrice)) {
tastockpriceList.add(taStockPrice);
}
}
....
}
#Entity
public class TaStockPrice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id
#Column
private Integer tastockid;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "tastockid", nullable = false, updatable = false, insertable = false)
private TaStock taStock;
...
}
persisting taStock with Children
#Test
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void createTaStock() throws Exception {
TaStock taStock = new TaStock();
...
TaStockPrice taStockPrice = new TaStockPrice();
...
taStock.addTaStockPrice(taStockPrice);
taStockService.persist(taStock);
}
I read that when persisting a parent class, hibernate automatically persist the children of that class. But instead, the following exception occurs:
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: ERROR: null value in column "tastockid" violates not-null constraint

I removed private Integer tastockid" from TaStockPrice, and modified
#JoinColumn(name = "tastockid", nullable = false, updatable = false, insertable = true) to solve it.

You are setting the collection as being not insertable nor updateable. This way hibernate will never persist it.
You could set how hibernate should treat this relation using the cascade-setting in your annotation. For more information, here is a thorough blog-post on the subject: http://www.mkyong.com/hibernate/hibernate-cascade-example-save-update-delete-and-delete-orphan/.

Use below annotation on tastockpriceList.
#OneToMany
#Cascade(CascadeType.ALL)
#JoinColumn(name="tastock")
That should resolve the problem.

In order to enable save ability on a #OneToMany relation e.g.
#OneToMany(mappedBy="myTable", cascade=CascadeType.ALL)
private List<item> items;
Then you have to tell to your #ManyToOne relation is allowed to update myTable like this updatable = true
#ManyToOne
#JoinColumn(name="fk_myTable", nullable = false, updatable = true, insertable = true)

Related

#ManyToOne relationship is not audited

I have two entities:
#Entity
#Table(name = "entity_a")
#Audited
public class EntityA {
#Column(name = "entity_a_uuid", columnDefinition = "char", updatable = false)
#Type(type = "uuid-char")
private UUID uuid = UUID.randomUUID();
/**
* #deprecated in favor of uuid
*/
#Deprecated
#Id
#GeneratedValue
#Column(name = "entity_a_id")
private Integer id;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "entity_a_id", nullable = false)
#BatchSize(size = 100)
#NotAudited
private List<EntityB> entityBs = new ArrayList<>();
}
and
#Entity
#Audited
#Table(name = "entity_b")
public class EntityB {
#Id
#Column(name = "entity_b_uuid", columnDefinition = "char", updatable = false)
#Type(type = "uuid-char")
private UUID uuid = UUID.randomUUID();
#ManyToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "entity_a_id", nullable = false, insertable = false, updatable = false)
private EntityA entityA;
}
Each is correctly audited into two tables entity_a_audit and entity_b_audit. However, the entity_a_id field in entity_b_audit is always null.
Some details:
If I do not have the #NotAudited in EntityA, I will get an error that says something to the effect of: The table EntityA_EntityB_audit does not exist. This seems like it's trying to audit them as a single table, which I do not want.
I have tried applying #Audited(targetAuditMode = elationTargetAuditMode.NOT_AUDITED) to each side. If applied only in EntityA, I get the above error. If applied only in EntityB, nothing changes. If applied in both, I get the error above. If applied to neither, I get the error above.
I suspect the entity_a_id is null in entity_b_audit because the id isn't generated until EntityA hits the DB. entity_a_id is auto-incrementing in the entity_a table.
Using hibernate-envers-5.4.32.Final.jar
Ultimately, I would like for entity_a_id to not be null in entity_b_audit. Alternatively, if I could somehow get entity_a_uuid to be captured instead, that would also suffice.
Any help would be greatly appreciated! Thanks.
You marked the column as insertable = false, updatable = false, so there is nothing to audit here, because Hibernate can never change the value of that column.

jpa one to one relationship issue when persist

I have 2 models with one to one relationship
#Entity
#Table(name = "Form_Item_Production")
public class FormItemProduction {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "item_id", nullable = false)
private Long itemId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "shift_lookup_id", insertable = false, updatable = false)
private AppLookup appLookup;
getter and setter
}
The other one
#Entity
#Table(name = "App_Lookup")
public class AppLookup {
#Id
#GeneratedValue
#Column(name = "Lookup_Id", nullable = false)
private Long lookupId;
#Column(name = "Lookup_Name", length = 30, nullable = false)
private String lookupName;
getter and setter
}
When I try to persist to save the formitemproduction values
public boolean insertItem(List<FormItemProduction> f) {
for (FormItemProduction i : f) {
System.out.println("A" + i.getAppLookup().getLookupId()); // prints the correct id of applookup
i.setItemId(null);
entityManager.persist(i);
}
entityManager.flush();
return true;
}
I get this error
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.mamee.factory.security.entity.AppLookup
From my understanding this is unidirectional one to one mapping so I don't quite understand why I'm getting the error detached?
You have itemId which can't be null.
#Column(name = "item_id", nullable = false)
private Long itemId;
and you actually set itemId to null
i.setItemId(null);
So this line
entityManager.persist(i);
Is not able to persist your data.
Fixed by changing from:
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "shift_lookup_id", insertable = false, updatable = false)
private AppLookup appLookup;
to:
#OneToOne
#JoinColumn(name = "shift_lookup_id", insertable = true, updatable = true)
private AppLookup appLookup;
You have set cascade to ALL:
#OneToOne(cascade = CascadeType.ALL)
Which means you are cascading all operations down to the related field AppLookup.
You can set cascade to none, and you will no longer get your error, but no db operations will be executed for AppLookup field.

JPA insertable = false updatable = false id not updated on creation

We have 2 entities with a #ManyToOne relationship.
When we create an instance of EntityB within a #Transactional method, entityAId (insertable = false updatable = false), is not updated automatically - even though that the entityA instance was already persisted.
Is there a way around this? Do we have to update it manually in the ctor?
#Entity
public class EntityA {
#Id
#GeneratedValue
private Long id;
public EntityA() {
super();
}
...
}
#Entity
public class EntityB {
#Id
#GeneratedValue
private Long id;
#ManyToOne(optional = true, fetch = FetchType.LAZY)
private EntityA entityA;
#Column(name = "entityA_id", insertable = false, updatable = false)
private Long entityAId;
public EntityB() {
super();
}
public EntityB(EntityA entityA) {
super();
this.entityA = EntityA;
}
...
}
EDIT: Also tried the following, but still entityAId = null within the transaction (even though entityA was persisted before).
#Entity
public class EntityB {
#Id
#GeneratedValue
private Long id;
#ManyToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "entityA_id", insertable = false, updatable = false)
private EntityA entityA;
#Column(name = "entityA_id")
private Long entityAId;
...
}
Hibernate is not going to populate entity fields 'on the fly' (when you change some other fields or similar). It is also not going to do it on persist/flush (exceptions being some special fields like id and version).
Non-insertable/non-updatable fields are populated when entity instances are fetched from the DB. So, to make such fields initialized/refreshed by Hibernate in the same transaction in which you perform changes to the underlying columns they are mapped to, you should first flush the session and then either:
clear the session and re-read the entities;
or, refresh the entities for which you want to reflect such kind of changes.
To update the id field a persist action of the object is required. By default, objects in field entityA are not automatically persisted when persisting an object of EntityB.
I see two possible solutions:
A) Use cascade
#ManyToOne(optional = true, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST})
private EntityA entityA;
(or use CascadeType.ALL)
B) Persist entityA manually
entityManager.persist(entityA);
To me your mapping does not look right. #ManyToOne or any other association defined between entities but you have defined it on entityAId. Ideally it should be entity (an here you should use insertable = false updatable = false)and you should have separate field entityAId with #column defined on it. Now you should update this field yourself.
If you want to handle hibernate for you remove insertable = false updatable = false

Hibernate, JPA cant delete one-to-many relation

I have one-to-many relation:
#Entity
#Table(name = "Users")
public class User {
#Id
#Column(name = "user_id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "login", nullable = false)
private String login;
#Column(name = "password", nullable = false)
private String password;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "role_id", nullable = false)
private Role role;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = javax.persistence.CascadeType.ALL)
private Set<Contacts> contacts = new HashSet<Contacts>();
And I'm trying to delete User object with all Contacts; I tried to use:
cascade = javax.persistence.CascadeType.ALL
cascade =
javax.persistence.CascadeType.REMOVE
#Cascade(CascadeType.DELETE) from org.hibernate.annotations
#Cascade(CascadeType.DELETE_ORPHAN) from org.hibernate.annotations
but nothing helped. I always get exception:
org.hibernate.util.JDBCExceptionReporter - Cannot delete or update a
parent row: a foreign key constraint fails
(contactmanager.contact, CONSTRAINT contact_ibfk_1 FOREIGN KEY
(user_id) REFERENCES
UPD
Code that deletes a User is as follows:
#Transactional
public void removeUser(User user) {
sessionFactory.getCurrentSession().delete(user);
}
I'll appreciate any help! Thanks.
My recommendation here would be to do the relationship management yourself. Cascading removes can be tricky (especially in a situation like yours where the owner of your bi-directional relationship is not the one declaring the cascade) and often times quite dangerous so I usually prefer to avoid them. Especially if you are running a version of JPA pre-2.0 then you don't have too much of a choice. I would just change the removal method to something like:
#Transactional
public void removeUser(User user) {
Set<Contacts> contacts = user.getContacts();
for (Contact contact : contacts) {
sessionFactory.getCurrentSession().delete(contact);
}
contacts.clear();
sessionFactory.getCurrentSession().delete(user);
}

Hibernate: delete records from association table with foreign keys

I'm new in hibernate. So, I don't know how to do this:
I have 3 tables:
Table Person:
#Entity
#Table(name = "ASD_PERSON")
public class AsdPerson implements Serializable {
#Id
#SequenceGenerator(name="seq_name", sequenceName="gen_id_value", allocationSize = 1)
#GeneratedValue(generator="seq_name")
#Column(name="F_PERSON_ID", nullable = false)
private Long fPersonId;
#OneToMany(mappedBy = "AsdPerson",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<AsdPersonEvent> asdPersonEventList;
... setters and getters ...
}
Table Event:
#Entity
#Table(name = "ASD_EVENT")
public class AsdEvent implements Serializable {
#Id
#SequenceGenerator(name="seq_name", sequenceName="gen_id_value", allocationSize = 1)
#GeneratedValue(generator="seq_name")
#Column(name="F_EVENT_ID", nullable = false)
private Long fEventId;
#OneToMany(mappedBy = "AsdEvent",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<AsdPersonEvent> asdPersonEventList;
... setters and getters ...
}
Table Person-Event:
#Entity
#Table(name = "ASD_PERSON_EVENT")
#IdClass(AsdPersonEventPK.class)
public class AsdPersonEvent implements Serializable {
#Id
#GenericGenerator(name = "generator", strategy = "foreign",
parameters = #Parameter(name = "property", value = "asdPerson"))
#GeneratedValue(generator = "generator")
#Column(name="F_PERSON_ID", nullable = false, insertable = false,
updatable = false)
private Long fPersonId;
#Id
#GenericGenerator(name = "generator", strategy = "foreign",
parameters = #Parameter(name = "property", value = "asdEvent"))
#GeneratedValue(generator = "generator")
#Column(name="F_EVENT_ID", nullable = false, insertable = false,
updatable = false)
private Long fEventId;
#ManyToOne
#JoinColumn(name = "F_PERSON_ID", insertable = false,
updatable = false)
private AsdPerson asdPerson;
#ManyToOne
#JoinColumn(name = "F_EVENT_ID", insertable = false,
updatable = false)
private AsdEvent asdEvent;
... setters and getters ...
}
Everything works perfectly (adding new records, creating new objects) except the case, when I try to delete associated records from Event table or Person table:
...
AsdEvent ev = getService().get(115); // get record from Event table by id = 115 (for example)
ev.getAsdPersonEventList().remove(1); // delete some existing records
getService().merge(ev);
...
After that I get error:
deleted object would be re-saved by
cascade (remove deleted object from
associations):
[database.AsdPersonEvent#database.AsdPersonEventPK#12908fc]
How to configure Hibernate with annotations or some other way to get rid of this error?
If you have a complex graph of persistent entities, I think you need to give up using orphanRemoval and remove your entities manually using em.remove().
orphanRemoval is designed for simple parent-child relationships, where child doesn't make sense without parent. If in your case child may have ohter relationships, perhaps it's not a good case for orphanRemoval.
Try once again by removing orphanRemoval = true

Categories