I am getting the following exception when I try to update an object:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: ......
Can anyone help???
The object that I am trying to update has the 'lazy' attribute set to false in the mapping file. Seems like hibernate is expecting me to save child objects before it flushes the update???
EDIT (ADDED):
<hibernate-mapping>
<class name="utils.message.Message" table="messages">
<id name="id" column="message_id">
<generator class="native" />
</id>
<property name="message_text" column="message_text" />
<property name="message_file" column="message_file" />
<property name="is_active" column="is_active" type="boolean"/>
<property name="is_global" column="is_global" type="boolean"/>
<property name="start" column="start" type="java.util.Date"/>
<property name="end" column="end" type="java.util.Date"/>
<property name="last_updated" column="last_updated" type="java.util.Date"/>
<many-to-one name="last_updated_by" class="utils.user.User" column="last_updated_by" lazy="false"/>
<many-to-one name="healthDepartment" class="utils.healthdepartment.HealthDepartment" column="health_department_id" lazy="false"/>
</class>
</hibernate-mapping>
TransientObjectException occurs when you save an object which references another object that is transient (meaning it has the "default" identifier value, frequently null) and then flush the Session. This commonly happens when you are creating an entire graph of new objects but haven't explicitly saved all of them. There are two ways to work around this:
As you suggest, you could use cascading of saves to other associated objects. However, cascading wasn't really intended as a workaround for TOE but rather as a convenience for saving a group of related objects that are frequently manipulated together. If you detach your objects without its full set of associated data and then save it with cascading enabled, you could inadvertently delete data you don't want to lose.
Ensure that all transient objects in your graph are explicitly saved as part of your unit of work. This is really just a case of understanding how your application will be creating an object graph and what entities are transient and which might be persistent or detached.
I would recommend reading this entire chapter from the Hibernate docs to understand fully the terminology of transient, persistent and detached:
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/objectstate.html
dude use property "cascade = true" in mapping. all will well...
V-Boy
With a many-to-one relationship, it would not be appropriate for Hibernate to cascade persistence operations, since the "one" is conceptually an entity shared between many others. This kind of relationship isn't a "child object", as you put it.
You can override this behaviour by explicitly setting the cascade attribute on the relation, or you can manually persist the other end of the many-to-one relations.
App is in a Spring environment. Fix: to run update from within Hibernate environment.
Related
I'm working with Hibernate 4.3.5, Java 1.6 and Spring 4.0.3.
I've mapped the entities through hbm, and I want my application works with logical deletion.
So, in each mapped entity, I've added a property named 'deleted', which indicates if an entity is deleted or not.
Because I don't want to load the deleted entities (the ones having true the deleted property), I've used the where clause in the mapped classes, so I only get the entities aren't logically deleted.
And also, I've added the same where clause to every one-to-many relationship.
In one particular case, I've got a Report entity that has a one-to-many relationship with the Document entity.
So, when I mark a Document as deleted, and I save the Report entity (with merge), I expect than the Report entity doesn't keep the Document marked as deleted. But this doesn't occur.
This is the hbm for the Report entity:
<hibernate-mapping>
<class
name="es.entities.Report"
table="reports"
dynamic-insert="false"
dynamic-update="false"
where="deleted = 0">
<id name="id">
<generator class="identity"/>
</id>
<property name="title"></property>
<property name="deleted"></property>
<set
name="documents"
table="documents"
cascade="all"
lazy="false"
where="deleted=0">
<key column="id_report"/>
<one-to-many class="es.entities.Document"/>
</set>
</class>
</hibernate-mapping>
Here it is the hbm for the Document entity:
<hibernate-mapping>
<class
name="es.entities.Document"
table="documents"
dynamic-insert="false"
dynamic-update="false"
where="deleted = 0">
<id name="id">
<generator class="identity"/>
</id>
<property name="name"></property>
<property name="type"></property>
<property name="size"></property>
<property name="deleted"></property>
</class>
</hibernate-mapping>
I use a Service (ReportService) to open a Spring transaction. The method is:
#Autowired
private ReportDao reportDao;
#Transactional
public Report save(Report report) {
this.reportDao.save(report);
}
And this is the DAO (ReportDao) method I use to save the Report entity:
public Report save(Report report) {
return (Report) this.currentSession().merge(report);
}
I put an example:
The parameter I send to the service contains a Report object, with two Document objects, one of them deleted and the other not.
The DAO method returns the same information, but I'd like this method returns only the documents are not deleted.
Note: if I use another method with another transaction, I obtain the report only with the document is not deleted, but I'd like to do this in the same transaction.
Can anybody help me or show me an alternate to this? It is possible to use other Session method than merge?
Thanks a lot.
Merge method create a copy from the passed entity object and return it. Try re-fetching the report entity post merge.
When I try to delete an entry from a db, using
session.delete(object)
then I can the following:
1) If the row is present in DB then two SQL queries are getting executed: A select and then a delete
2) If the row is not present in the DB then only the select query is getting executed
But again this is not the case for update. Irrespective of the presence of DB row, only the update query is getting executed.
Please let me know why this kind of behaviour for delete operation. Isn't it a performance issue since two queries are getting hit rather than one?
Edit:
I am using hibernate 3.2.5
Sample code:
SessionFactory sessionFactory = new Configuration().configure("student.cfg.xml").buildSessionFactory();
Session session = sessionFactory.openSession();
Student student = new Student();
student.setFirstName("AAA");
student.setLastName("BBB");
student.setCity("CCC");
student.setState("DDD");
student.setCountry("EEE");
student.setId("FFF");
session.delete(student);
session.flush();
session.close();
cfg.xml
<property name="hibernate.connection.username">system</property>
<property name="hibernate.connection.password">XXX</property>
<property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:#localhost:1521/orcl</property>
<property name="hibernate.jdbc.batch_size">30</property>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<property name="hibernate.cache.use_query_cache">false</property>
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.connection.release_mode">after_transaction</property>
<property name="hibernate.connection.autocommit">true</property>
<property name="hibernate.connection.pool_size">0</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
hbm.xml
<?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="com.infy.model.Student" table="STUDENT">
<id name="id" column="ID">
<generator class="assigned"></generator>
</id>
<property name="firstName" type="string" column="FIRSTNAME"></property>
<property name="lastName" type="string" column="LASTNAME"></property>
<property name="city" type="string" column="CITY"></property>
<property name="state" type="string" column="STATE"></property>
<property name="country" type="string" column="COUNTRY"></property>
</class>
The reason is that for deleting an object, Hibernate requires that the object is in persistent state. Thus, Hibernate first fetches the object (SELECT) and then removes it (DELETE).
Why Hibernate needs to fetch the object first? The reason is that Hibernate interceptors might be enabled (http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/events.html), and the object must be passed through these interceptors to complete its lifecycle. If rows are delete directly in the database, the interceptor won't run.
On the other hand, it's possible to delete entities in one single SQL DELETE statement using bulk operations:
Query q = session.createQuery("delete Entity where id = X");
q.executeUpdate();
To understand this peculiar behavior of hibernate, it is important to understand a few hibernate concepts -
Hibernate Object States
Transient - An object is in transient status if it has been
instantiated and is still not associated with a Hibernate session.
Persistent - A persistent instance has a representation in the
database and an identifier value. It might just have been saved or
loaded, however, it is by definition in the scope of a Session.
Detached - A detached instance is an object that has been persistent,
but its Session has been closed.
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/objectstate.html#objectstate-overview
Transaction Write-Behind
The next thing to understand is 'Transaction Write behind'. When objects attached to a hibernate session are modified they are not immediately propagated to the database. Hibernate does this for at least two different reasons.
To perform batch inserts and updates.
To propagate only the last change. If an object is updated more than once, it still fires only one update statement.
http://learningviacode.blogspot.com/2012/02/write-behind-technique-in-hibernate.html
First Level Cache
Hibernate has something called 'First Level Cache'. Whenever you pass an object to save(), update() or saveOrUpdate(), and whenever you retrieve an object using load(), get(), list(), iterate() or scroll(), that object is added to the internal cache of the Session. This is where it tracks changes to various objects.
Hibernate Intercepters and Object Lifecycle Listeners -
The Interceptor interface and listener callbacks from the session to the application, allow the application to inspect and/or manipulate properties of a persistent object before it is saved, updated, deleted or loaded.
http://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/listeners.html#d0e3069
This section Updated
Cascading
Hibernate allows applications to define cascade relationships between associations. For example, 'cascade-delete' from parent to child association will result in deletion of all children when a parent is deleted.
So, why are these important.
To be able to do transaction write-behind, to be able to track multiple changes to objects (object graphs) and to be able to execute lifecycle callbacks hibernate needs to know whether the object is transient/detached and it needs to have the object in it's first level cache before it makes any changes to the underlying object and associated relationships.
That's why hibernate (sometimes) issues a 'SELECT' statement to load the object (if it's not already loaded) in to it's first level cache before it makes changes to it.
Why does hibernate issue the 'SELECT' statement only sometimes?
Hibernate issues a 'SELECT' statement to determine what state the object is in. If the select statement returns an object, the object is in detached state and if it does not return an object, the object is in transient state.
Coming to your scenario -
Delete - The 'Delete' issued a SELECT statement because hibernate needs to know if the object exists in the database or not. If the object exists in the database, hibernate considers it as detached and then re-attches it to the session and processes delete lifecycle.
Update - Since you are explicitly calling 'Update' instead of 'SaveOrUpdate', hibernate blindly assumes that the object is in detached state, re-attaches the given object to the session first level cache and processes the update lifecycle. If it turns out that the object does not exist in the database contrary to hibernate's assumption, an exception is thrown when session flushes.
SaveOrUpdate - If you call 'SaveOrUpdate', hibernate has to determine the state of the object, so it uses a SELECT statement to determine if the object is in Transient/Detached state. If the object is in transient state, it processes the 'insert' lifecycle and if the object is in detached state, it processes the 'Update' lifecycle.
I'm not sure but:
If you call the delete method with a non transient object, this means first fetched the object from the DB. So it is normal to see a select statement. Perhaps in the end you see 2 select + 1 delete?
If you call the delete method with a transient object, then it is possible that you have a cascade="delete" or something similar which requires to retrieve first the object so that "nested actions" can be performed if it is required.
Edit:
Calling delete() with a transient instance means doing something like that:
MyEntity entity = new MyEntity();
entity.setId(1234);
session.delete(entity);
This will delete the row with id 1234, even if the object is a simple pojo not retrieved by Hibernate, not present in its session cache, not managed at all by Hibernate.
If you have an entity association Hibernate probably have to fetch the full entity so that it knows if the delete should be cascaded to associated entities.
instead of using
session.delete(object)
use
getHibernateTemplate().delete(object)
In both place for select query and also for delete use getHibernateTemplate()
In select query you have to use DetachedCriteria or Criteria
Example for select query
List<foo> fooList = new ArrayList<foo>();
DetachedCriteria queryCriteria = DetachedCriteria.forClass(foo.class);
queryCriteria.add(Restrictions.eq("Column_name",restriction));
fooList = getHibernateTemplate().findByCriteria(queryCriteria);
In hibernate avoid use of session,here I am not sure but problem occurs just because of session use
I'm trying to use hibernate to fill my jsf selectonemenu in ApplicationBean (in Liferay). The problem is that I got Initial SessionFactory creation failed problem. Before putting my functions in the applicationbean I was setting them in sessionbean and I got no error.
For now the full error
Initial SessionFactory creation failed.
java.lang.ClassCastException: org.hibernate.type.StringType cannot be cast to org.hibernate.type.VersionType
You have very likely a VARCHAR column called VERSION somewhere and Hibernate's reverse engineering tool generates it as:
<version name="version" type="string">
<column name="VERSION" length="20" />
</version>
instead of:
<property name="version" type="string">
<column name="VERSION" length="20" />
</property>
The former is wrong. First, I think that this is not what you want. Second, a string is not allowed for a version field as mentioned in the chapter 5.1.9. Version (optional):
Version numbers can be of Hibernate type long, integer, short, timestamp or calendar.
This problem has been somehow reported in HHH-3002 (actually, it should be assigned to Hibernate Tools, not Hibernate Core) and I see two ways to solve it. Either
fix the mapping manually
rename the column to something else.
The property on one of your domain classes that you've mapped as the class's version is of type string. This is not a valid type for a version. What to change it to will depend on how you are implementing versioning in your underlying database.
I have seen posts all over the internet that talk about how to fix the TransientObjectExceptions during save/update/delete but I am having this problem when calling list on my Criteria.
I have two objects A and B. A has a field named b which is of type B. In my mapping b is mapped as a many-to-one. This all runs in a larger persistence framework (the framework is kind of like Core Data) and so I don't use any cascades in my hibernate mappings since cascades are handled at a higher level.
This is the interesting code surrounding my criteria:
A a = new A();
B b = new B();
a.setB(b);
session.save("B", b); // Actually handled by the higher level
session.save("A", a); // framework, this is just for clarity
// transaction committed and session closed
...
// new session opened
Criteria criteria = session.createCriteria(A.class);
criteria.add(Restrictions.eq("b", b));
List<?> objects = criteria.list();
Basically I am looking for all objects of type A such that A.b equals a particular instance of b (I actually tried restructuring a query so that I was passing in the id of b just to make sure that b wasn't causing me problems).
Here is the stack trace that occurs when I call criteria.list():
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: B
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:244)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:449)
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:141)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1769)
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:1740)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1612)
at org.hibernate.loader.Loader.doQuery(Loader.java:717)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:270)
at org.hibernate.loader.Loader.doList(Loader.java:2294)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2172)
at org.hibernate.loader.Loader.list(Loader.java:2167)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1706)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)
Here is my mapping:
<class entity-name="A" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
<many-to-one name="b" entity-name="B" column="b_id" lazy="false" />
</class>
<class entity-name="B" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
</class>
Can anyone help me figure out why I would be getting a TransientObjectException during a fetch? Preferably I would like to find a solution that does not rely on cascades since they tend to mask problems that occur in the higher level framework.
The problem is that b was made persistent in another session, which is closed and the query is created in a new session. When a session is closed, all objects in its persistence context become detached. If you want to later reuse them in another session, you need to re-attach them to that session first:
session.update(b);
Quote from the Hibernate book:
The update() operation
on the Session reattaches the detached object to the persistence context and
schedules an SQL UDPATE. Hibernate must assume that the client modified the
object while it was detached. (Otherwise, if you’re certain that it hasn’t been modified,
a lock() would be sufficient.) The persistence context is flushed automatically
when the second transaction in the conversation commits, and any
modifications to the once detached and now persistent object are synchronized
with the database.
The saveOrUpdate() method is in practice more useful than update(),
save(), or lock(): In complex conversations, you don’t know if the item is in
detached state or if it’s new and transient and must be saved. The automatic
state-detection provided by saveOrUpdate() becomes even more useful when you
not only work with single instances, but also want to reattach or persist a network
of connected objects and apply cascading options.
Note that there is also a merge() method, for cases when the same entity has been loaded into the new persistence context before the older detached instance could be re-attached. In this case, you have two physically distinct instances representing the same entity, thus they should be merged to avoid a NonUniqueObjectException.
Another easy way accomplish the same is to use the attribute cascade=all on the collection mapping of child class from within the parent class mapping. Here's how the mapping looks
<class entity-name="A" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
<many-to-one name="b" entity-name="B" column="b_id" lazy="false" cascade="all" />
</class>
<class entity-name="B" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
</class>
Since you have insert data such as in persist(),save() in hibernate..But the above error is you have just do merge() and others method which can perform the update information.
I have an entity that I want to persist through Hibernate (3.2)
The EntityBean has a column that indicates how another value of the entity bean should be unmarshalled:
<class name="ServiceAttributeValue" table="service_attribute_value">
<cache usage="nonstrict-read-write"/>
<id name="id" column="id" type="int-long">
<generator class="native"/>
</id>
<property name="serviceAttribute" type="service-attribute" column="service_attribute" not-null="true" />
<!-- order is important here -->
<property name="value" type="attribute-value" not-null="true">
<column name="service_attribute" />
<column name="id_value"/>
<column name="enum_value"/>
<column name="string_value"/>
<column name="int_value"/>
<column name="boolean_value"/>
<column name="double_value"/>
</property>
</class>
The "service_attribute" column indicates which of the columns for the "value" property to look at when it unmarshalls the value and, more importantly, exactly what Type the value should be, for example the class of the Enum if the enum_value is to be read, or the type of Bean if the the id_value is to be read.
The value property uses a custom CompositeUserType to do the unmarshalling and within this I wish to reference the service_attribute column (although not write to it), however when I try to do this I get the following error:
org.hibernate.MappingException: Repeated column in mapping for entity: com.precurse.apps.rank.model.service.ServiceAttributeValue column: service_attribute (should be mapped with insert="false" update="false")
However within the definition of the composite property these xml attributes are not defined (only within a normal property).
Does anyone know of a way of overcoming this, or if there is a better solution to this propblem.
If you need any more information please let me know,
Cheers
Simon
I had a similar problem and changing the case of one column solved the problem. Could give a try!
e.g., one column could be service_attribute other Service_Attribute.
You can try this. Instead of mapping both values as property on the same table, map one of the property using join to itself and keep the other property as the way it is. This case you will be able to access the same property in both places. Just remember to name the property as different name.
<join table="service_attribute_value">
<key column = "id" />
<property name="serviceAttribute" type="service-attribute" column="service_attribute" not-null="true" />
</join>
<!-- order is important here -->
<property name="value" type="attribute-value" not-null="true">
<column name="service_attribute" />
<column name="id_value"/>
<column name="enum_value"/>
<column name="string_value"/>
<column name="int_value"/>
<column name="boolean_value"/>
<column name="double_value"/>
</property>
based on your description, it seems like what you want to do is creating different subclasses based on the service_attribute. Instead of trying to achieve repeated column mapping which is not allow in hibernate, you can take a look hibernate inheritance mapping.
I Think I found a solution albeit not a very elegant one.
in the
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
method of the CompositeUserType the "owner" argument passed to the method contains the id of the object who's service_attribute I want to access.
Annoyingly the actual serviceAttribute of the owner is not accessable or has not been set at this stage (I played around with the ordering of the elements in the hbm.xml config, in case this was an ordering thing, but unfortunatly still no joy), so I can't simply access it.
Anyway the id of the owner object is set, so I then used the session argument to run a HQL query based on the id to access the serviceAttribute which I then used to correctly unmarshall the value property.
The drawback of this solution is that it requires a HQL query as an overhead to the unmarshalling process, although its within the same session, its still not optimal.
If anyone has any ideas for a better solution I'd be very grateful.
Cheers