An app I'm working on is using Oracle and Hibernate as ORM. When I'm trying to insert PartyUserObject I keep getting following errors:
could not insert: [Person]; SQL [insert into PARTY (............)]; constraint [PARTY_FK1]
java.sql.SQLIntegrityConstraintViolationException: ORA-02291: integrity constraint (PARTY_FK1) violated - parent key not found
The message seems to be obvious, but I can't configure Hibernate to get it working.
Relevant entities' relations and hbm.xml files are as follows:
PartyUser.java
private Party ap;
Party.java
private Address address;
private Set<PartyUser> partyUsers;
PartyUser.hbm.xml
<many-to-one
name="ap"
column="AP_ID"
class="Party"
not-null="true"
lazy="false"
cascade="save-update,evict">
</many-to-one>
Party.hbm.xml
<set name="partyUsers" inverse="true" fetch="subselect">
<key column="AP_ID"/>
<one-to-many class="PartyUser"/>
</set>
PARTY_FK1 refers to address FK in the party table. As I said before save is called on the DAO for a newly instantiated PartyUser object (associated Party and Address objects are new as well). All ids are generated on the java side. As you probably noticed both entities has cascade turned on.
Any ideas what's wrong?
I am not sure as to why this happens, but I see this error all the time. What I have been doing is at the beginning, when I add all of my data, first I turn off constraints with: SET DATABASE REFERENTIAL INTEGRITY FALSE and then at the end I just turn it back on SET DATABASE REFERENTIAL INTEGRITY TRUE. Not so much a fix, as it is a hack, but it works for us so I thought I would share the knowledge.
FYI, it turned out that hibernate was configured to use db sequence generation, but ids in turn were preassigned in the java code. fmdl
Related
we have a big problem in our development team.
We are using Hibernate and we have some entities which are related in two transitive one-to-many relations. The main object is a Group which has a list of Property instances, and each Property containing a list of Values.
(The mappings are down ahead)
We have two main problems:
A) When making a HQL Query, Criteria Query or SQLQuery it doesn't matter the conditions applied in JOINs or WHERE clauses, Hibernate always retrieves for us all the underlying objects. For example, if I make a Criteria or SQL getting only the Group objects, Hibernate comes and (lazy or not) gets all the Property and Value instances too. We want to control this. We want to do left joins and get only the properties with no values inside (Hibernate removes these properties with no value)
B) When making the Query, for example, a SQL, it shows in the log the SQL code we want. Everything seems perfect. But after that it brings every instance in the list without applying conditions, getting them only by id, and we can assure this because with lazy="true" we see the "load many-to-one" queries in the log.
Is there something we can do in hibernate config, fetching mode/strategy, the mappings configuration or anywhere? I'm thinking on going on Result transformers now.
I would be grateful if someone coud give me a hint or tell me where to find a solution to this problem. We are confused about how to get this, but it must be a way.
Thanks in advance
Query:
Criteria lstCriterios = this.getSession().createCriteria(CardGroup.class, CARD_GROUP)
.add(Restrictions.eq(ID_CATEGORY, idCategory));
lstCriterios.createAlias("listProperty", "listProperty", CriteriaSpecification.LEFT_JOIN);
if (clusterId != null) {
lstCriterios.add(Restrictions.or(
Restrictions.isNull("listPropertyValue" + ".value"),
Restrictions.and(Restrictions.eq("listPropertyValue" + ".clusterId", clusterId),
Restrictions.eq("listPropertValue" + ".companyWarehouseId", idCompanyWarehouse))));
lstCriterios
.createAlias("listProperty" + "." + "listPropertyValue", "listPropertyValue",
CriteriaSpecification.LEFT_JOIN,
Restrictions.eq("listPropertyValue" + ".clusterId", clusterId));
} else {
lstCriterios.createAlias("listProperty" + ".listPropertyValue", "listPropertyValue",
CriteriaSpecification.LEFT_JOIN);
}
lstCriterios.add(Restrictions.eq(ID_CATEGORY, idCategory));
lstCriterios.add(Restrictions.eq("listProperty" + ".groupId", idGroup));
lstCriterios.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
/*
* Sorting
*/
lstCriterios.addOrder(Order.asc("order"));
lstCriterios.addOrder(Order.asc("listProperty" + ".order"));
lstCriterios.addOrder(Order.asc("listPropertyValue"+ ".clusterId")); // Agrupacion, podrĂa ser nulo
lstCriterios.addOrder(Order.asc("listPropertyValue"+ ".propertyId")); // Propiedad
lstCriterios.addOrder(Order.asc("listPropertyValue"+ ".id"));
return lstCriterios.list();
Group mapping:
<list name="listProperty"
table="FICHA_PROPIEDAD" schema="${db2.siglo.schema}"
inverse="false" cascade="all" >
<key column="ID_FICHA_GRUPO" not-null="false" />
<list-index column="ORDEN" base="1"/>
<one-to-many
class="com.company.aslo.appwebsiglo.model.card.property.property.CardProperty" />
</list>
Property mapping:
<bag name="listPropertyValue"
table="FICHA_PROPIEDAD_VALOR" schema="${db2.siglo.schema}"
inverse="false" cascade="all">
<key column="ID_FICHA_PROPIEDAD" not-null="false" />
<one-to-many
class="com.company.aslo.appwebsiglo.model.card.propertyvalue.propertyvalue.CardPropertyValue" />
</bag>
It seems like our model design was bad and we didn't realize that if the DB table FICHA_PROPIEDAD_VALOR has Composite Key we can't map only one of the attributes in the composite key, because it brings us unexpected results.
Because of this and the nested objects, we had also bad implementations of the hashCode() and equals() methods which Hibernate uses.
I had solved this previously with a ResultTransformer getting the rows from a SQLQuery, but we got the Hibernate solution after that refactoring and changing the design of our model.
As per Hibernate docs for one-to-many xml mapping tag there is an attribute called as not-found
http://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html/collections.html#collections-onetomany
The Doc says:
not-found (optional - defaults to exception): specifies how cached
identifiers that reference missing rows will be handled. ignore will
treat a missing row as a null association.
What is the use of this attribute? I tried to create a mapping between Product and Parts with Product having a set of Parts with below mapping details:
<set name="parts" cascade="all">
<key column="productSerialNumber" not-null="true" />
<one-to-many class="Part" not-found="ignore"/>
</set>
Then I wrote my Java code as:
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Product prod = (Product) session.get(Product.class, 1);
session.getTransaction().commit();
System.out.println(prod);
HibernateUtil.getSessionFactory().close();
}
I was expecting null for my set which has Parts as I configured in my mapping file as not-found="ignore". But I got the regular exception - org.hibernate.LazyInitializationException
Please help me in understanding what is the use of this attribute? What are cached identifiers here?
The not-found has nothing to do with lazy loading. It's used to handle incoherences in your database.
Suppose you know nothing about good database practices, and have an order_line table containing an order_id column, supposed to reference the order it belongs to. And suppose that since you know nothing about good practices, you don't have a foreign key constraint on this column.
Deleting an order will thus be possible, even if the order has order lines referencing it. When loading such an OrderLine with Hibernate, Hibernate will load the Order and fail with an exception because it's supposed to exist, but doesn't.
Using not-found=ignore makes Hibernate ignore the order_id in the OrderLine, and will thus initialize the order field to null.
In a well-designed database, this attribute should never be used.
I have two tables Item and Property and one item can have multiple properties. I have modeled it correctly (i think) in hibernate and when loading the ItemModel object, all the properties load properly.
The problem is when I am trying to delete properties and then save it, the properties just get added to the existing ones.
ItemModel m = ...;
m.getPropertySet().size() // returns 5 initially
m.getPropertySet().clear();
// some update function which adds properties
m.getPropertySet().size(); // returns 1
...currentSession().saveOrUpdate(m);
What happens is that now the database has 6 properties for that category instead of 1. What should I do to make this work?
The model for Item's mapping to properties looks something like this
<set name="propertySet" cascade="all">
<key column="item_id" not-null="true"/>
<one-to-many class="Property"/>
</set>
Use cascade="all-delete-orphan". See the first example in the reference guide for a walkthrough of relationships like this. Also, if this is a bidirectional one-to-many, then this side (the set) should be mapped with inverse="true" so that the relationship is determined solely based on the other side of the relationship.
I would like to evaluate JPA on an existing project. The database model and the java classes exists and are currently mapped via self generated code. The database model and the java classes do not fit ideally together - but the custom mapping works well. Nevertheless the usage of JPA in general seems worth a try.
As you see I am new to JPA and have to do the work with xml configuration. Currently I am working on a one-to-many unidirectional relationship using a join table (please do not discuss this szenario here).
A (one - relationship owner) <-> AB (JoinTable) <-> B (many)
The tables look like this
A
--
ID
BREF
...
B
--
ID
...
AB
--
A_BREF (foreign key to a reference column in A which is NOT the id)
B_ID
I would like to define a unidirectional one-to-many relationship for class A.
class A {
private List<B> bs;
}
and did it like this:
<one-to-many name="bs">
<join-table name="ab">
<join-column name="a_bref">
<referenced-column-name name="bref" />
</join-column>
<inverse-join-column name="b_id">
<referenced-column-name name="id" />
</inverse-join-column>
</join-table>
</one-to-many>
Althoug this does not force an error it is not working. The problem is that the join table does not work on the ID column of A. The query to select the "B" entities works with the A.ID column value instead of the A.BREF column value to select the entities.
(How) can I make this mapping work (I use eclipselink 2.2.0)?
Thanks for any suggestion!
EDIT:
After looking at a link provided in #SJuan76 answer I slightly modified my mapping to
<one-to-many name="bs">
<join-table name="ab">
<join-column name="a_bref" referenced-column-name="bref" />
<inverse-join-column name="b_id" referenced-column-name="id" />
</join-table>
</one-to-many>
This now causes the following errors (tested with eclipselink 2.1.0 and 2.2.0)
eclipselink 2.1.0
Exception Description: The parameter
name [bref] in the query's selection
criteria does not match any parameter
name defined in the query.
eclipselink 2.2.0
Exception Description: The reference
column name [bref] mapped on the
element [field bs] does not
correspond to a valid field on the
mapping reference.
By the way - if I remove the referenced-column-name="bref" from the definition I get the same exception for the referenced-column-name="id" on the inverse-join-column element. So I doubt that I have understood referenced-column-name correct. I used it to specify the database column name of the tables which are related to the join table. Is this correct?
SOLUTION:
The final error in my szenario was that I did not have the BREF field definied in my class
class A {
private long bref; // missing !
private List<B> bs;
}
and in my orm.xml mapping file for this class
<basic name="bref">
<column name="bref" />
</basic>
I was not aware that I have to define the used join mapping referenced-column-name attributes somewhere in my mapping classes (as I also did not have the join-table itself or the name attributes of join-column/inverse-join-column mapped to a class or class members.)
Also the tip to check the case issue was helpful for me. I feel now quite to verbose in specifying my mapping as I overwrite all default (uppercase) mappings with lowercase values. As my database is not case sensitive I will use upper case notation if special mapping is needed to go with the default.
+1 for all!
Can you try defining the field as "BREF" or the same exact case used if you defined it on the attribute mapping, or you can try setting the eclipselink.jpa.uppercase-column-names persistence property to true. This is likely the issue with "id" when referenced-column-name="bref" is removed, since it is likely the field in the entity defaults to "ID".
In general JPA requires that the foreign keys/join columns reference the primary key/Id of the Entity. But, this should work with EclipseLink, so please include the SQL that is being generated, and if it is wrong, please log a bug.
How is the Id of A defined, is it just ID or ID and BREF?
You can use a DescriptorCustomizer to customize the ManyToManyMapping for the relationship and set the correct foreign key field name.
I have the following two table (which are tied in with Spring security - but the issue I believe is with Hibernate):
Table user
Table authority
The user table is tied (through Hibernate) to a domain object in my application: class User, which has the following attributes (and corresponding getters and setters), which correspond to columns in the user table (except for the Collection which is explained later):
long uId
String username
String password
...
Collection<GrantedAuthority> authorities
The authority table has 2 columns: UserId (foreign key into user table), and Authority (e.g. "ROLE_USER"). This table is NOT represented as a domain object, but is simply a collection in the User class.
To create the mapping, in my .hbm file I use the following:
<class name="com.business.project.domain.User" table="user">
<id name="uId" column="UserId"></id>
<property name="username" column="Name" type="java.lang.String" />
<property name="password" column="Password" type="java.lang.String" />
...
<set name="authorities" table="authority">
<key column="UserId" />
<element column="Authority" type="java.lang.String" />
</set>
</class>
In my hibernate DAO implementation, I create a query object, execute the query, and cast the result to a User object:
...
Query query = session.createQuery("from User where name = :username");
...
User user = (User) query.uniqueResult();
At this point, I would expect this object to be populated with the data that it pulled from the DB (I made sure that the tables are populated properly with test data and the mapping names are correct in the mapping file).
However, calling the getter methods for various attributes on the user object all return NULL for some reason. Can somebody see something immediately wrong with my setup? Perhaps I mapped the collection (to foreign key relationship) wrong? THANKS!
Update: here is the sql query that hibernate generated (taken from its DEBUG output):
Hibernate: select user0_.UserId as UserId1_, user0_.Name as Name1_,
user0_.Password as Password1_ from user user0_ where user0_.Name=?
For some reason, it doesn't show anything related to the authority table...does this mean that my mapping is incorrect?
Edit: Per bozho's suggestion, I took a look at the messages on the consol on startup (tomcat), but didn't see anything out of the ordinary:
Feb 16, 2010 10:35:12 AM org.hibernate.cfg.HbmBinder bindRootPersistentClassCommonValues
INFO: Mapping class: com.me.project.domain.User -> user
Feb 16, 2010 10:35:12 AM org.hibernate.cfg.HbmBinder bindCollection
INFO: Mapping collection: com.me.project.domain.User.authorities -> authority
Query query = session.craeteQuery("FROM User WHERE username = :username");
query.setString("username", "SomeUserName");
That should pretty much do it.
Try with "from User where username = :username"
HQL uses class properties, not db column names
Are you clearing the database everytime you run the test/java code? In hibernate there is a setting and when it is turned on, it can clear the database everytime a test/java code is run.
Can you do a findAll() and print the size? I very much suspect it is the wrong db, or no data in the db or clearing of data.
NOTE: Check for "hibernate.hbm2ddl.auto" property in your config file. If it is set to "create-drop" hibernate will auto create the schema on startup and delete the schema when VM shuts down. Just point it to "update" or something
http://docs.atlassian.com/hibernate2/2.1.8/reference/session-configuration.html
"Password" usually is a keyword in databases. It seems like you're hitting a name collision problem. Try the following. Put tick mark around the column name for escaping.
<property name="username" column="`Name`" type="java.lang.String" />
<property name="password" column="`Password`" type="java.lang.String" />
Assume you're using org.springframework.security.GrantedAuthority, then your mapping for authorities is incorrect. Based on the way you're mapping, when you access the collection, you most likely will get a ClassCastException. You probably want to use something like UerType to avoid the problem.