I'm using Hibernate mapping to config stages in my application. It's configured that the necessary class (here called Configurator) is injected with the stages.
I have one list containing Object Score:
private List<Score>dsScore = new ArrayList<Score>(0);
I have a database containing table Score and a list in class Student and student.hbm.xml as:
`<list name ="dsScore" table="SCORE">
<key>
<column name="SCORE_ID" not-null="true"></column>
</key>
<one-to-many class="model.Score"/>
</list>`
into a file config Student containing it, it not work.
Can anybody help me with this?
list hibernate type is collection with persisted ordering. It
requires explicit mapped column in underlying table for ordering, so
your mapping is missing <index>/<list-index> element. OR you
should use bag (maybe with order-by attribute) to get collection
mapped to java List without persisting order. See docs
Use package
attribute on <hibernate-mapping> instead of qualified class name.
I assume that both Student and Score classes are in model package. The mapping then should look like
<hibernate-mapping package="model">
<class name="Student" table="...">
...
<bag name="dsScore" table="Score" order-by="...">
<key column="SCORE_ID" />
<one-to-many class="Score" />
</bag>
</class>
</hibernate-mapping>
Related
I have a legacy hibernate application (using hibernate 3.2.6.ga) where we fetch information similar to the structure below. We have a person who contains several other attributes like address details or bank accounts or transactions.
Person
List of Address Details
List of bank accounts
List of transactions
and many more...
With a hibernate mapping file like this:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="myPkg.Person" table="PERSON" schema="WhatEver" lazy="false">
<id name="personId" type="java.lang.Long">
<column name="PERSON_ID" precision="1" />
<generator class="sequence">
<param name="sequence">some_sequence_generator</param>
</generator>
</id>
<!-- lazy init is true as only some methods is interested in addressDetails-->
<bag name="addressDetails" inverse="true" cascade="all" lazy="true">
<meta attribute="propertyType">java.util.LinkedList</meta>
<key>
<column name="PERSON_ID" precision="10" not-null="true" />
</key>
<one-to-many class="myPkg.Address" />
</bag>
...
<!-- lazy init is true as a person can have billion transactions -->
<bag name="transactionDetails" inverse="true" cascade="all" lazy="true">
<meta attribute="propertyType">java.util.LinkedList</meta>
<key>
<column name="PERSON_ID" precision="10" not-null="true" />
</key>
<one-to-many class="myPkg.transaction" />
</bag>
</class>
</hibernate-mapping>
We have several methods to retrieve the persons. Some requires that the child related data be returned as well and some not. So all in the mapping file is set to lazy=”true”.
In cases where we are interested in the children right after we return the data we do a Hibernate.initialize(personObjectJustReturned) to go and fetch the children as well:
Person personInstance = (Person) getHibernateTemplate().get(Person.class, new Long(id));
Hibernate.initialize(personInstance);
But the problem comes in with the transactions list as this can become a very large set of data - where a person can have billions of transactions.
What I would like to do is never return transactions with the person object at all.
So I can do one of 2 things:
Simply make everyting eagerly loaded in my XML file by setting lazy=”false” (apart from my transactions) and don’t do a Hibernate.initialize(personObjectJustReturned). But that would mean that any other method returning data will eagerly fetch the child data as well as all methods in the app is using the same hibernate mapping. Which is not ideal as for example not all methods requires address details. So I will be fetching more data than required on a global scale which is bad practice.
Remove the transactions field relationship from my config file so hibernate will not even know about the transactions field when it retrieving a person. This will work perfectly but in cases where we save a person object and that person has newly generated transactions we will have to save the transactions separately. Aka we cannot simply tell hibernate go and save the person object which automatically saves the newly generated transactions as hibernate don't know about the relationship anymore.
Is there a better way to do this?
The first option you show can lead to memory consumption problems if you have a lot of children per object.
The best option then, is to load the children fetched by the parent object:
SELECT * FROM transaction_detail WHERE person = ?
This way you avoid the Hibernate.initialize(personObjectJustReturned) and fetch the details more precisely (sorted or more filtered).
Then, to save a new transactionDetail, the TransactionDetail object must have the Person object set (as the parent) and when saving (the save will be done at the TransactionDetail), no error should happen (the foreign keys will avoid orphans).
As the subject says I want to map a HashMap with a List as a value in Hibernate.
Since it looks like it is not possible to have a collection as element in a map in Hibernate, I have created a class that contains a list of Ids.
My HashMap looks like this:
Map<Status, IdList> statusIdsMap = new HashMap<Status, IdList>();
Status is either insert/update/remove. IdList contains a List of Ids.
Hibernate mapping looks like this:
<id name="id" type="IdType" />
...
<map name="statusIdMap">
<key column="id" />
<map-key type="Status" column="StatusCode" />
<element type="IdList" />
</map>
...
<class name="IdList" select-before-update="true" table="IdList">
<id name="id" column="id" unsaved-value="null">
<generator class="IdGenerator"/>
</id>
<set name="Ids" table="IdsForStatus">
<key column="id"/>
<element column="updatedId" type="IdType"/>
</set>
</class>
If I try to store the class with statusIdMap, Hibernate generates an Insert SQL that tries to put the IdList class in a column, instead of the Id to the IdList class.
The Hibernate error message says "expected number, got binary".
It's related question to this
Hibernate(JPA) mapping a HashMap
where the answer suggests to put list in the Key class, but it's not something I wish to do.
Any other suggestions?
EDIT:
In short the test does following:
Fills object with dummy values, including map.
Initializing hibernate and starts a transaction
Inserts object
Commits transaction and closes hibernate session
The error message comes from the database when trying to commit, since the generated insert statement is wrong as mentioned above.
I have the following relationship: Form --[order]-- Attribute.
One form has n attributes and an attribute can belong to n forms. The relation requires to save an extra property : order.
So I have a class form, a class attribute and a class form_attribute like this:
public class FormAttribute{
Form form;
Attribute attribute;
int attrOrder;
// getters/setters
}
On the Form mapping I am mapping like this:
<set name="attributes" table="form_attribute" inverse="true" cascade="all-delete-orphan" order-by="attrOrder" >
<key column="form" not-null="true"/>
<composite-element class="FormAttribute" >
<many-to-one name="attribute" column="attribute" class="ExamAttribute" not-null="true" cascade="save-update" />
<property name="attrOrder" column="attr_order" type="integer" not-null="true" />
</composite-element>
</set>
when I create a new form and associate attributes I expect when, I save, to see the form_attribute table populated. But only form and attribute table is. Is it normal? Do I have to manually update the form_attribute relationship?
So, finally it was a bit of a stupid issue. If I do not save attribute first and since there is no set on the attribute side to manage the link between form and attribute, the composite element was not saved. Saving the new attributes first, then saving the form fixed my issue.
I am sure there is a hibernate term for this but I am not sure what it is (and I could therefore probably look up the answer) but here goes.
I have a Product Pojo where one of the fields is a Set of Suppliers (also a Pojo). When I call to get a list of Products, by default it queries to get the list of Suppliers- which is what I would expect.
However, sometimes I do not require the data in the Set and the querying it is taking too long to just bear it. Is there a way to sometimes avoid querying the data for the Set?
Or is my design incorrect?
My Product.hbm.xml mapping file has:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field" default-lazy="false" package="model">
<class name="model.Product" table="PRODUCT">
<id column="PRODUCT_ID" name="id" type="long">
<generator class="native" />
</id>
...
<set name="suppliers" sort="unsorted" table="SUPPLIERS">
<key column="PRODUCT_ID" />
<one-to-many class="model.Suppliers" />
</set>
...
</class>
</hibernate-mapping>
The default behavior of Hibernate is what you are expecting: All collections mapped for an entity, and all associated entities, be it through to-many or to-one associations, are not loaded by default.
But if you have defined the lazy="false" for the Set of Suppliers, Hibernate will fetch the associated collection eagerly along with the Product.
Change the suppliers mapping as below, so that Hibernate will not fetch it eagerly:
<set name="suppliers" sort="unsorted" table="SUPPLIERS" lazy="true">
<key column="PRODUCT_ID" />
<one-to-many class="model.Suppliers" />
</set>
EDIT:
The above mapping is the default fetching strategy for suppliers. Now if you want to load suppliers along with the Product, you can override this default strategy at runtime in code:
String productSelect = "select p from Product "
+ "p left join fetch p.suppliers "
+ "where p.productName=:pname";
Query query = session.createQuery(productSelect);
query.setParameter("pname", productname);
Product result = (Product) query.uniqueResult();
The above query will fetch the Product along with the set of suppliers. So, wherever needed, you can override the default strategy by using above query to get suppliers along with Product.
Set the fetchtype to LAZY (instead of EAGER) for the supplier Set.
I've created a UserObject and RoleObject to represent users in my application. I'm trying to use hibernate for CRUD instead of raw JDBC. I've successfully retrieved the information from the data base, but I can not create new users. I get the following error.
org.springframework.web.util.NestedServletException: Request processing failed; nested
exception is org.springframework.dao.DataIntegrityViolationException: could not insert:
[com.dc.data.UserRole]; nested exception is
org.hibernate.exception.ConstraintViolationException: could not insert:
[com.dc.data.UserRole]
My data base is defined as follows:
Users Table, Authority Table and Authorities table. Authorities table is a join of users and authority.
My hibernate mapping for UserObjec is as follows:
...
<set name="roles" table="authorities" cascade="save-update" lazy="false" >
<key column="userId" />
<one-to-many class="com.dc.data.UserRole"/>
<many-to-many class="com.dc.data.UserRole" column="authId" />
</set>
</class>
...
UserRole is mapped as follows:
<class name="com.dc.data.UserRole" table="authority">
<id name="id" column="authId">
<generator class="native" />
</id>
<property name="roleName">
<column name="authority" length="60" not-null="true" />
</property>
</class>
How do I need to change my mapping or Object structure to be able to persist new users?
You are defining two different relationships inside of your "set" element. What you probably want is just the many-to-many element.
If this still doesn't work, try saving the UserRole itself to see if you can persist it on its own. If you can, then the ConstraintViolationException is being thrown while trying to persist User.
Last tip, you probably don't want to cascade save/update on the "roles" Set. In all likelihood your UserRoles will already be in the DB and simply be attached to the Users as they get created.
The contraint violation on UserRole might be a cause of trying to insert a row with a duplicate key. Maybe experiment with using other types of generators, such as "sequence".