The #JoinColumns on the annotated element [...] from the entity class [...] is incomplete - java

I make use of: NetBeans IDE 6.7.1, GlassFish v2.1, Oracle 10g XE, JAVA 6 SE, JAVA 5 EE.
I have problem with an #ManyToMany annotation:
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name="CUST_RENT_MOVIE", joinColumns={#JoinColumn(name="CUST_ID")}, inverseJoinColumns={#JoinColumn(name="TITLE")})
private Collection<CustRentMovie> rents = new ArrayList<CustRentMovie>();
part of the output of the GlassFish v2.1.1
Exception Description: The #JoinColumns on the annotated element [private java.util.Collection vc.domain.Customer.rents] from the entity class [class vc.domain.Customer] is incomplete. When the source entity class uses a composite primary key, a #JoinColumn must be specified for each join column using the #JoinColumns. Both the name and the referenceColumnName elements must be specified in each such #JoinColumn.
javax.persistence.PersistenceException: Exception [TOPLINK-28018] (Oracle TopLink Essentials - 2.1 (Build b31g-fcs (10/19/2009))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
Exception Description: predeploy for PersistenceUnit [vc_pu] failed.
part of the script that create the database:
CREATE table customer
(
cust_id NUMBER(5),
CONSTRAINT cust_pk PRIMARY KEY (cust_id),
...
)
CREATE TABLE movie
(
title VARCHAR2(50) PRIMARY KEY,
...
)
CREATE TABLE cust_rent_movie
(
title VARCHAR2(50),
cust_id NUMBER(5),
rent_date DATE DEFAULT current_date NOT NULL,
return_date DATE,
CONSTRAINT cust_rent_movie_pk PRIMARY KEY (title, cust_id, rent_date),
CONSTRAINT CustRentMovie_movie_fk FOREIGN KEY (title) REFERENCES movie ON DELETE CASCADE,
CONSTRAINT CustRentMovie_cust_fk FOREIGN KEY (cust_id) REFERENCES customer ON DELETE CASCADE
)
the code of the Customer class
#Entity
#Table(name = "customer")
#SequenceGenerator(name="seq", sequenceName="cust_id_seq", allocationSize=1)
public class Customer implements Serializable
{
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
#Column(name="CUST_ID")
private int id;
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name="CUST_RENT_MOVIE", joinColumns={#JoinColumn(name="CUST_ID")}, inverseJoinColumns={#JoinColumn(name="TITLE")})
private Collection<CustRentMovie> rents = new ArrayList<CustRentMovie>();
public Collection<CustRentMovie> getRents()
{
return rents;
}
public void setRents(Collection<CustRentMovie> rents)
{
this.rents = rents;
}
...
}
by mistake I put as type in the collection the class CustRentMovie instead of Movie So I changed the
private Collection<CustRentMovie> rents = new ArrayList<CustRentMovie>();
to
private Collection<Movie> movies = new ArrayList<Movie>();

CustomerRentMovie's PK is made up of three columns (title, cust_id, rent_date). Toplink is indicating that you need to specify all three as join columns in your #JoinColumn annotation (currently you have specified only cust_id).
Changing the annotation to something like this should get you past this error.
#JoinTable(name = "CUST_RENT_MOVIE", joinColumns = {
#JoinColumn(name = "CUST_ID"),
#JoinColumn(name = "TITLE"),
#JoinColumn(name = "RENT_DATE") }, inverseJoinColumns = { #JoinColumn(name = "TITLE") })
private Collection<CustRentMovie> rents = new ArrayList<CustRentMovie>();
That said, Pascal's question is valid - it looks like you intended to have a relationship from Customer to Movie, not Customer to CUST_RENT_MOVIE.

by mistake I put as type in the collection the class CustRentMovie instead of Movie So I changed the
private Collection<CustRentMovie> rents = new ArrayList<CustRentMovie>();
to
private Collection<Movie> movies = new ArrayList<Movie>();

Related

Is it possible to use #JoinTable over a subclass that includes target + join fields?

My model (exemplified) is the following:
CREATE TABLE person (
id INT PRIMARY KEY,
name TEXT
...
);
CREATE TABLE team (
id INT PRIMARY KEY,
name TEXT
....
);
CREATE TABLE team_reference_persons (
team_id INT NOT NULL,
person_id INT NOT NULL,
uses_telephone BOOLEAN,
PRIMARY KEY (team_id, person_id),
FOREIGN KEY (team_id) REFERENCES team(id),
FOREIGN KEY (person_id) REFERENCES person(id)
);
And my JPA defintion:
#Entity
#Table(name = "team")
public class Team {
#Id
private Integer id;
#OneToMany
#JoinTable(name = "team_reference_persons", joinColumns = #JoinColumn(name = "team_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "person_id", referencedColumnName = "id"))
private List<Person> teamReferencePersons;
...
}
#Entity
#Table(name = "person")
public class Person {
#Id
private UUID id;
private String name;
...
}
So far, so good, when all you need is the person list on the team. But now I need to add the team_reference_persons.uses_telephone property from the join table in my person domain, So I am looking for a way to keep the persons logic, while I create a new subclass.
private class TeamIndividual extends Person {
boolean uses_telephone;
}
Then changing List<Person> on Team entity by List<TeamIndividual>. Is that possible someway? JPA should be indicated in such smart way that it adds the join table property to the final target entity (on both read and save).
No need to extend TeamIndividual to Person.
Annotate TeamIndividual with #Table(name = "team_reference_persons")
Define fields(teamId,personId,uses_telephone) inside TeamIndividual
Annotate fields teamId and PersonId with #ManyToOne and #JoinColumn
Add List to Team without annotation
Try this,It will work..!!

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

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

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!

Hibernate OrphanRemoval is deleting data only from Relationship table

I have a RECIPE table that has OneToMany relationship with the INGREDIENT table because a single recipe can have many ingredients. The issue is that if a user deletes an ingredient (which sets all fields (ingredient_id and ingredient) to NULL by frontend), then the row containing relationship of both the tables RECIPE_INGREDIENT is deleted but the row in the Ingredient table still exists. Can't we tell Hibernate to delete that rows also?
Oracle table
create table recipe(id number primary key,
name varchar2(25) unique);
create table ingredient(ingredient_id number(4) primary key,
ingredient varchar2(40));
create table recipe_ingredient(recipe_id number(4),
ingredient_id number(4),
constraint recipe_fk foreign key(recipe_id)
references recipe(recipe_id),
constraint ingredient_fk foreign
key(ingredient_id) references
ingredient(ingredient_id));
Ingredient and Recipe POJO
#Entity
#Table(name = "ingredient", uniqueConstraints={
#UniqueConstraint(columnNames="INGREDIENT_ID")
})
public class Ingredient implements Serializable {
#Id
#Column(name = "INGREDIENT_ID", unique=true, nullable=false)
#SequenceGenerator(name="seq_ingredient", sequenceName="seq_ingredient")
#GeneratedValue(strategy=GenerationType.AUTO, generator="seq_ingredient")
private Integer ingredientId;
#Column(name = "INGREDIENT")
private String ingredient;
/*#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="RECIPE_ID")
private Recipe recipe;*/
//getter and setters
#Entity
#Table(name = "recipe")
public class Recipe implements Serializable {
#Id
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
#JoinTable(name = "recipe_ingredient", joinColumns = { #JoinColumn(name = "recipe_id") }, inverseJoinColumns = { #JoinColumn(name = "ingredient_id") })
private List<Ingredient> ingredients;
//getters and setter
}
DAO Code
public class RecipeDaoImpl implements RecipeDao {
public void addRecipe(Recipe recipe) {
getSession().saveOrUpdate(recipe);
}
}
Log that shows that the row in INGREDIENT table still exists whereas Hibernate is just deleting row from 'RECIPE_INGREDIENT' table.
Please see following that ingredient_id with null is deleted. In both cases, it is updating ingredient.recipe_id as NULL.
Received following from frontend:
RecipeController - Recipe[recipeId=126,name=Sandwich,ingredients=[Ingredient[ingredientId=270,ingredient=Salt],[ingredientId=<null>,quantity=<null>]]]
Hibernate: update RECIPE set NAME=? where RECIPE_ID=?
Hibernate: update ingredient set INGREDIENT=? where INGREDIENT_ID=?
Hibernate: delete from recipe_ingredient where recipe_id=?
Hibernate: insert into recipe_ingredient (recipe_id, ingredient_id) values (?, ?)
So the database table has,
INDREDIENT
INGREDIENT_ID INGREDIENT
271 Salt
272 Sugar
RECIPE_INDGREDIENT
RECIPE_ID INDREDIENT_ID
126 271
Have you implemented the equals() and hashcode() methods correctly in the Receipe and Indgredient classes? If not then that could be the cause why the rows in indgredient table are not deleted. Read this article for more details.

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);

Categories

Resources