PK not found while saving collection of entities (bug ??) - java

i have ORA-02291 while creating new object (entitymanager.persist(taskVisit))
#Entity(name = "CRM_TASKDEPARTURE")
#Access(AccessType.PROPERTY)
#DiscriminatorValue(value = TaskType.Consts.VISIT_ID)
public class TaskVisit extends Task {
private static final long serialVersionUID = 1L;
private List<TaskVisitAddress> addresses = new ArrayList();
public TaskVisit() { }
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.PERSIST,mappedBy = "taskVisit")
public List<TaskVisitAddress> getAddresses() {
return addresses;
}
}
Connstraint is CRM_TaskVisitAddress(TASKID)
Code of entity:
#Entity(name = "CRM_TaskDepartureAddress")
public class TaskVisitAddress implements Serializable {
...any fields
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TASKID")
public TaskVisit getTaskVisit() {
return taskVisit;
}
#Id
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PERSONADDRESSID")
public PersonAddress getPersonAddress() {
return personAddress;
}
}
Exception:
Error Code: 2291
Call: INSERT INTO CRM_TASKDEPARTUREADDRESS (TASKID, PERSONADDRESSID) VALUES (?, ?)
bind => [3299, 1]
Caused by: java.sql.SQLIntegrityConstraintViolationException: ORA-02291: integrity constraint (DUMMY.FK_CRM_TASKDEPARTUREADDR_TASKI) violated - parent key not found
Where is the mistake?
P.s. in test object saved without exception...
Updated
I found wrong INSERT generated sequence
1. insert into superclass Task (right)
2. insert into CRM_TaskDepartureAddress (wrong)
3. insert into CRM_TASKDEPARTURE (wrong)
№ 2 and 3 must be swaped, becouse CRM_TaskDepartureAddress referenced to CRM_TASKDEPARTURE .
Updated
InheritanceType.JOINED

You cannot have a ManyToOne as your primary key; it is stating that there are many TaskVisitAddress instances referencing the same TaskVisit, while your #Id requires something that is unique.
You need to find something on your TaskVisitAddress that will uniquely identify it from other TaskVisitAddress instances, such as Integer id assigned through sequencing.
The #JoinColumn(name = "TASKID") is referring to "TASKID" in the Task table, as JPA only allows relationships to reference an Entity's primary key, making the constraint requiring CRM_TASKDEPARTURE to be inserted first is incorrect. If you must keep the constraint and require CRM_TASKDEPARTURE to be inserted first, you can try specifying the table name in the joinColumn:
#JoinColumn(name = "TASKID", referencedColumnName = "CRM_TASKDEPARTURE.TASKID")
as described in feature request
https://bugs.eclipse.org/bugs/show_bug.cgi?id=333100

Related

Can't insert null values on #ManyToOne relationship

I'm getting this error when I try to persist an A class Object:
Detail: Key (classB)=() is not present in table "b".
I need to have the possibility to insert the object with null on the referenced column.
The problem is hibernate convert the null value on an empty string, so when I try to persist the object, it fails.
If I put cascade = CascadeType.ALL on #ManyToOne works, but it creates a row on B table with ID = 0 and an empty string as refColName value. I want to avoid this because de A class is the child, and the cascade should be in B class.
#Entity
#Table
public class A {
...
#ManyToOne
#JoinColumn(name = "class_b", referencedColumnName = "refColName", nullable = true)
private B classB;
...
}
#Entity
#Table
public class B {
...
#Id
#Column (name = "id")
private long id;
#Column(name = "refColName")
private String refColName;
...
}
Any suggestion?
Thanks for your time
Edit:
It's a unidirectional relationship, where B is a master data table, so i have predefined values. refColName should be a String. I use referencedColumnName because I can´t take the id as a foreign key.
I need to have the possibility to insert the object with null on the
referenced column.
Please make sure the classA input to persist should be like below(representing in json)
{
classB:null
}
and not
{
classB:{
refColName:null
}
}

Hibernate JPA, one to one relationship with a composite key and a constant value

I'm attempting to implement a limited type of object level ACL and its lead me to a place where I'm attempting to create a #OneToOne relationship using a composite key with a constant and dynamic value.
I have an Entity with a database id and a constant value defined in the class.
public class Entity{
private static final int objectType = 1;
#Id
Integer id;
}
I have an access_levels table with a composite key of objectId and objectType.
public class AccessLevel {
#EmbeddedId
private AccessLevelKey accessLevelKey;
#Embeddable
class AccessLevelKey implements Serializable{
private Integer objectType;
private Integer objectId;
....
}
}
Schema of access_levels
CREATE TABLE access_levels(
object_type INTEGER NOT NULL,
object_id INTEGER NOT NULL,
....
CONSTRAINT access_levels_type_id PRIMARY KEY (object_type, object_id)
);
I'm attempting to come up with a one to one relationship that Entity can use to fetch and update its associated AccessLevel
After taking a look a the docs on Non-Standard Joins it seems like I need something like this,
Inside of Entity:
#OneToOne
#JoinColumns({
#JoinColumn(name = "id", referencedColumnName = "object_id"),
#JoinColumn(name = "access_levels.object_type", referencedColumnName = "1"),
})
private AccessLevel accessLevel;
However this throws a hibernate MappingException at app launch
Caused by: org.hibernate.MappingException: Unable to find column with logical name: 1 in access_levels
Thanks!

Java hibernate: Update foreign key in manytoone relationship automatically

I have a problem with the auto update of foreign keys which appears as following:
I have a two tables HamKeyword and HamKeywordAlias. One entry in the hamKeyword has 0…n entries in HamKeywordAlias. This relationship is reflected with a foreign key field in the HamKeywordAlias table. Both tables have their own primary keys. I defined the two tables using reverse engineering of hibernate eclipse tools as follows:
#Entity
#Table(name = "HAM_KEYWORDS")
public class HamKeywords implements java.io.Serializable {
private long keywordid;
private String keyword;
…
#Id
#GenericGenerator(name="gen",strategy="increment")
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "KEYWORDID", unique = true)
public long getKeywordid() {
return this.keywordid;
}
…
#OneToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL, mappedBy = "hamKeywords")
public Set<HamKeywordsAlias> getHamKeywordsAliases() {
return this.hamKeywordsAliases;
}
#Entity
#Table(name = "HAM_KEYWORDS_ALIAS", schema = "dbo", catalog = "ham")
public class HamKeywordsAlias implements java.io.Serializable {
#Id
#GenericGenerator(name="gen",strategy="increment")
#GeneratedValue(generator="gen")
#Column(name = "ALIASID", unique = true, nullable = false)
public long getAliasid() {
return this.aliasid;
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "KEYWORDID", nullable = false, updatable = false, insertable = true)
public HamKeywords getHamKeywords() {
return this.hamKeywords;
}
Now to my problem. I try to add a new entry to HamKeyword with 1 new related HamKeywordAlias:
HamKeywords hkw = new HamKeywords();
HamKeywordsAlias hka = new HamKeywordsAlias();
hka.setAlias("new alias");
hkw.setHamKeywordsAliases(new HashSet<HamKeywordsAlias>());
Set<HamKeywordsAlias> hkaS = hkw.getHamKeywordsAliases();
hkaS.add(hka);
hkw.setHamKeywordsAliases(hkaS);
session.flush();
session.save(hkw);
session.getTransaction().commit();
This code fails with the error message:
ERROR: The value NULL can not be inserted in table 'KEYWORDID'-Spalte, 'ham.dbo.HAM_KEYWORDS'. No NULL allowed for INSERT. Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not execute statement
(Please note that I translated the error message into english, it might be a bit different languagewise)
Obviously, the foreign key in field KEYWORDID of the HamKeywordAlias table is not be updated. I double checked this by removing the NOT NULL constraint. What happens is, that the enty into the ALIAS table is inserted but with a NULL in the field keywordid.
I tested furthermore adding manually rows into the HamKeywordAlias table. Retrieving an entry of the HamKeyword table and retrieving the related Aliases with following code works great:
HamKeywords hamCurrentKeyword = (HamKeywords) session.get(HamKeywords.class, (long)1);
hamCurrentKeyword.getHamKeywordsAliases();
Thus I assume that I defined the many to one relation correctly. However, the foreign key is not updated automatically.
Can you assist me why this is not be done?
Thanks
Felix
You have a bidirectional OneToMany association. The owner of the association is the Many side: HamKeywordsAlias.hamKeywords. That's the side that Hibernate cares about. But you didn't initialize it. You added an alias to the keywords' collection of aliases, but failed to set the keywords of the alias:
hka.setHamKeywords(hkw);

JPA Join using arbitrary field (not primary key)

I've got two entities that I want to join together using a field they have in common, called shared_id. The field is not the primary key of either entity. The shared_id is unique - each Hipster will have a unique shared_id.
The tables look like:
Hipster Fixie
========= ========
id id
shared_id shared_id
There is a OneToMany relationship between Hipsters and their Fixies. I've tried something like this:
#Entity
public class Hipster {
#Id
#Column(name = "id")
private Integer id;
#Column(name = "shared_id")
private Integer sharedId;
#OneToMany(mappedBy = "hipster")
private List<Fixie> fixies;
}
#Entity
public class Fixie {
#Id
#Column(name = "id")
private Integer id;
#ManyToOne
#JoinColumn(name = "shared_id", referencedColumnName = "shared_id")
private Hipster hipster;
}
#Repository
public class HipsterDAO {
#PersistenceContext
private EntityManager entityManager;
public Hipster getHipsterBySharedId(Integer sharedId) {
String queryString = "SELECT h FROM Hipster h WHERE h.sharedId = :sharedId";
TypedQuery<Hipster> query = entityManager.createQuery(queryString, Hipster.class);
query.setParameter("sharedId", sharedId);
try {
return query.getSingleResult();
} catch (PersistenceException e) {
return null;
}
}
}
Now, my DAO gives me this error:
java.lang.IllegalArgumentException: Can not set java.lang.Integer field Hipster.sharedId to java.lang.Integer
I think it's upset because the sharedId field is used in a relation, rather than just being a basic field. I haven't included the sharedId field in the Fixie entity, but I get the same result if I do. How do I persuade it to run this query for me? Do I need to change the query or the entities?

Wrong SQL for view object using Hibernate Annotations

I'm working on a hibernate entity mapping for a database view; when I do a criteria query against it, hibernate is generating bad SQL. Any help figuring out what the problem is with my mapping would be greatly appreciated!
I have two mapped entities which I am trying to grab from a database view; the view has no other columns, just the FK of each entity. One of these FK's can be treated as a primary key, since the view has a row for each primary entity. So my DB schema for the view looks like:
primary(primary_id, some_other_fields)
history(history_id, primary_id, some_other_fields)
view_latest_status_history(primary_id, history_id)
Note the view is used because I want to pick out only the latest history for each primary, not all mapped history records. Here is the object I am using for the view, with entity annotations:
#Entity
#org.hibernate.annotations.Entity(dynamicUpdate = true)
#Table(name = "view_latest_status_history")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class ViewLatestStatusHistoryRow implements Serializable {
private Primary primary;
private History history;
/**
* #return Returns the history.
*/
#ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY)
#JoinColumn(name = "history_id", nullable = true)
#AccessType("field")
public History getHistory() {
return history;
}
//equals() and hashCode() implementations are omitted
/**
* #return Returns the primary.
*/
#Id
#ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY)
#JoinColumn(name = "primary_id", nullable = false)
#AccessType("field")
public Primary getPrimary() {
return primary;
}
}
Both the Primary and History objects have complete, working entity annotations.
My criteria setup:
criteria.add(Restrictions.in("primary", [collection of primary objects]));
criteria.setFetchMode("primary", FetchMode.JOIN);
criteria.setFetchMode("history", FetchMode.JOIN);
And the (wrong) generated SQL:
select this_.primary as primary78_1_, this_.primary_id as prim2_78_1_, primary2_.history_id as unique1_56_0_, ...history fields
from DB_CATALOG.dbo.view_latest_status_history this_
left outer join DB_CATALOG.dbo.history primary2_ on this_.primary_id=primary2_.primary_id
where this_.specChange in (?, ?...)
I might've mucked up a few things when editing out the specifics of our project's DB schema, but the point is the first field in the 'select' clause is wrong:
this_.primary (view_latest_status_history.primary) is not a field; the field should be called primary_id. I think this may have something to do with the #Id annotation on the primary field? Any ideas how to fix this? If I remove the #Id, I get an error telling me that the entity has no primary key.
Update:
I no longer map the view as a field using a join table notation (as suggested below). The annotations have been revised, as follows. This solution works correctly in HQL, and generates the expected schema when hbm2ddl is enabled, but I have not re-tested it using the criteria query.
#Entity
#Table(name = "view_latest_status_history")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class ViewLatestStatusHistoryRow implements Serializable {
private String id;
private Primary primary;
private History history;
/**
* #return Returns the history.
*/
#OneToOne(optional = true)
#JoinColumn(name = "history_id", nullable = true)
#AccessType("field")
public History getHistory() {
return history;
}
//equals() and hashCode() implementations are omitted
#Id
#Column(name = "primary_id", nullable = false)
#Override
#AccessType(value = "field")
public String getId() {
return id;
}
/**
* #return Returns the primary.
*/
#PrimaryKeyJoinColumn(name = "primary_id", referencedColumnName = "unique_id")
#OneToOne(optional = false)
#AccessType("field")
public Primary getPrimary() {
return primary;
}
}
It most certainly is due to #Id annotation - primary_id is NOT a primary key in this case. Nor can you realistically have #Id and #ManyToOne on the same property.
Let me ask you this - why are you mapping ViewLatestStatusHistoryRow as an entity to begin with? It's not like you ever going to persist it. Consider mapping your latest history entry directly (as read-only) on primary (as many-to-one) and using your view as join table.

Categories

Resources