I have a Product class which has a 1-to-many association to itself (composite pattern). Below are the pojo, hbm, test code and log/error respectively. Can someone explain what this error is about. Why am I getting this error when setting the parent's primary key?
Product pojo
public class Product
{
private Long id;
private Set<Product> children = Collections.emptySet();
public void addChild(final Product child)
{
if (children.isEmpty())
{
children = Sets.newHashSet();
}
child.setParent(this);
children.add(child);
}
}
hbm.xml
<class name="Product" table="PRODUCT">
<set name="children" lazy="false" table="PRODUCT">
<key>
<column name="ID" />
</key>
<one-to-many class="Product" />
</set>
</class>
Test
public void save()
{
// Level 1 - mortgage LOB
Product mortgage = new Product();
mortgage.setCode("Mortgage");
Product ml = new Product();
ml.setCode("Mortgage Loan");
Product me = new Product();
me.setCode("Home Equity LOC");
//Level 2
mortgage.addChild(ml);
mortgage.addChild(me);
hibernateTemplate.save(mortgage);
}
log and error
DEBUG [org.hibernate.SQL] insert into PRODUCT (ID, CODE, NAME, STARTDATE, ENDDATE, ISDECISIONABLE, ISSELECTABLE) values (null, ?, ?, ?, ?, ?, ?)
DEBUG [org.hibernate.type.StringType] binding 'Mortgage' to parameter: 1
DEBUG [org.hibernate.type.StringType] binding null to parameter: 2
DEBUG [org.hibernate.type.TimestampType] binding null to parameter: 3
DEBUG [org.hibernate.type.TimestampType] binding null to parameter: 4
DEBUG [org.hibernate.type.BooleanType] binding 'false' to parameter: 5
DEBUG [org.hibernate.type.BooleanType] binding 'false' to parameter: 6
DEBUG [org.hibernate.SQL] call identity()
DEBUG [org.hibernate.SQL] update PRODUCT set ID=? where ID=?
DEBUG [org.hibernate.type.LongType] binding '1' to parameter: 1
ERROR [org.hibernate.event.def.AbstractFlushingEventListener] Could not synchronize database state with session
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.Product
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:219)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:397)
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:78)
A transient object is one that has not been saved. As mapped, your relationship does not use any 'transitive persistence', that is to say, you have not told hibernate that when you save the parent you want to save the children. I guess the error is because you have instances of the children (doesn't matter that the children have the same class of the parent) on the parent (in the session), and hibernate is aware of that, but it doesn't know what to do with them.
You can either:
1) save the children before saving the parent
2) add the 'cascade' attribute to your mapping, something like cascade="save" or cascade="all"
see http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html#objectstate-transitive
well I don't think that is all your code rigth? because in your pojo you need to have getters and setters for your Set. And try to saveyour Product this way:
Set children=new HashSet();
Product p=new Product();
Product p1=new Product();
Product p2=new Product();
children.add(p1);
children.add(p2);
p.setChildren(children);
hibernateTemplate.save(p);
But put cascade="all" or cascade="save-update" in your set mapping.
Related
I'm unable to delete a child record while I'm updating (not deleting) the parent record. Also, I've read other posts, but it seems most of the others are using annotations rather than xml, so it can be difficult to see how they relate to my issue.
I have two tables: The EventInfo table that holds information about events and then the EventLicenseType table that only has two columns and both of those columns make up the primary key; one of the columns in the EventLicenseType table is a foreign key to the EventInfo table.
The problem is I can't seem to delete an EventLicenseType record. I've tried a bunch of different things and nothing is working for me. It seems like hibernate wants to put null as the eventinfoId column, which of course doesn't work. I have tried clearing out the Set and then doing the merge, and also specifically calling session.delete(eventlicenseTypeRec) and then doing the merge. Neither is working for me.
EventInfo.hbm.xml file:
<hibernate-mapping default-lazy="true">
<class name="Eventinfo" table="PA_EVENTINFO">
<id name="eventInfoId" type="int"
column="PA_EVENTINFOID">
<generator class="native" />
</id>
<property name="eventTypeId" type="java.lang.String"
column="PA_EVENTTYPEID" length="255" />
...Other columns not shown here for brevity...
<set name="eventLicenceTypeIds" lazy="false" cascade="all-delete-orphan">
<key column="PA_EVENTINFOID"/>
<one-to-many class="EventLicenseType" />
</set>
</class>
EventLicenseType.hbm.xml file:
<hibernate-mapping default-lazy="true">
<class name="EventLicenseType" table="PA_EVENTLICENSETYPE">
<composite-id>
<key-property name="licenseTypeId" type="java.lang.Integer" column="PA_LICENSETYPE"/>
<key-property name="eventInfoId" type="java.lang.Integer" column="PA_EVENTINFOID"/>
</composite-id>
</class>
Here is the EventInfo class. Again, there are more fields in the actual file, this is just the important pieces:
public class Eventinfo implements Serializable {
/** identifier field */
private int eventInfoId;
/** nullable persistent field */
#Field(name="eventInfo_eventTypeId")
private String eventTypeId;
#IndexedEmbedded
private Set<EventLicenseType> eventLicenceTypeIds;
/** default constructor */
public Eventinfo() {}
public int getEventInfoId() {
return this.eventInfoId;
}
public void setEventInfoId(int eventInfoId) {
this.eventInfoId = eventInfoId;
}
public String getEventTypeId() {
return this.eventTypeId;
}
public void setEventTypeId(String eventTypeId) {
this.eventTypeId = eventTypeId;
}
public Set<EventLicenseType> getEventLicenceTypeIds() {
return eventLicenceTypeIds;
}
public void setEventLicenceTypeIds(Set<EventLicenseType> eventLicenceTypeIds) {
this.eventLicenceTypeIds = eventLicenceTypeIds;
}
Here is the EventLicenseType class
public class EventLicenseType implements Serializable{
#Field
private int licenseTypeId;
private int eventInfoId;
public int getLicenseTypeId() {
return licenseTypeId;
}
public void setLicenseTypeId(int licenseTypeId) {
this.licenseTypeId = licenseTypeId;
}
public int getEventInfoId() {
return eventInfoId;
}
public void setEventInfoId(int eventInfoId) {
this.eventInfoId = eventInfoId;
}
}
Here is the method I'm executing in my DAO. For now there is only one record associated to the eventInfo record, so I'm just trying to see if I can delete that one. (Also note that eventinfo is defined in the method that surrounds this one).
public Eventinfo execute(Session session) throws Exception {
//Get the existing eventInfo record
Eventinfo existing = (Eventinfo)session.get(Eventinfo.class, eventinfo.getEventInfoId());
Iterator iter = existing.getEventLicenceTypeIds().iterator();
if (iter.hasNext()) {
EventLicenseType license = (EventLicenseType) iter.next();
iter.remove();
session.delete(license);
}
session.flush();
return (Eventinfo) session.merge(eventinfo);
}
On the above session.flush() line, I get an error: java.sql.BatchUpdateException: Cannot insert the value NULL into column 'PA_EVENTINFOID', table 'PA_EVENTLICENSETYPE'; column does not allow nulls. UPDATE fails. It shows that hibernate is trying to do:
update PA_EVENTLICENSETYPE set PA_EVENTINFOID=null where PA_EVENTINFOID=?
Why can't it just delete the record? Why is it trying to do an update??
I also tried changing the code to the below and get the same error.
public Eventinfo execute(Session session) throws Exception {
//Clear out the list
eventinfo.getEventLicenceTypeIds().clear();
return (Eventinfo) session.merge(eventinfo);
}
Can anyone help me with what I'm missing, or point me in the right direction?
You need to see whether the mapping between two tables are unilateral or bilateral. Basically you need to think or the rows of two tables as objects and cut all the ties between the objects of EventInfo and EventLicenceType tables. So if the relation is only from EventInfo -> EventLicenseType, you need to set the value of the EventLicenseType set to null in EventInfo object. Also if there is a mapping from EventLicenseType, you need to set the value of joining column to null. Then merge() the EventInfo object.
Noneed to explicitly delete or remove the EventLicenseType object. If here are no references to EventLicenseType object, the JVM will collect it as garbage.
Hope that solves your problem.
I need some help here, I am trying to return a list of objects, inside a parent object using myBatis.
THE PROBLEM :
Before you begin reading the code below - My error that I get back is :
SqlSession operation; nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4102
What is interesting here is that this somehow means I am hitting the stored procedure, seeing the amount of data there is, and erroring due to having too many results because myBatis thinks I am using selectOne() - Which is not true? I will add, that 4102 is the exact number of records in the table I am trying to pull this data from.
MY CODE :
Here are the result maps for the parent and child objects :
<resultMap id="ParentObjectMap" type="com.company.product.mybatis.model.ParentObject">
<collection property="children" resultMap="childrenMap"/>
</resultMap>
<resultMap id="childrenMap" type="com.company.product.mybatis.model.ChildObject">
<id column="ChildId" jdbcType="BIGINT" property="childId" />
<result column="Name" jdbcType="VARCHAR" property="name" />
</resultMap>
Here is the code for each of the above maps.
public class ParentObject implements Serializable {
private long id;
private List<ChildObject> childrenMap;
/* GETTERS AND SETTERS EXCLUDED FOR BREVITY. */
}
And the class for the Child object :
public class ChildObject implements Serializable {
private long childId;
private String name;
/* GETTERS AND SETTERS REMOVED FOR BREVITY. */
}
Here Is the Stored Procedure which I am calling, which aims to return the data :
ALTER PROCEDURE dbo.PR_Children_Get
AS
SET NOCOUNT ON
BEGIN
SELECT
tp.ChildId,
tp.Name
FROM dbo.Children tp WITH (NOLOCK)
END
GO
And here is how I am executing that procedure in my mapper :
<select id="getChildren" resultMap="ParentObjectMap">
exec [dbo].[PR_Children_Get]
</select>
Here is the interface through which I access my mapper :
#Override
public ParentObject getChildren() throws Exception {
ParentObject result = ParentObjectMapper.getChildren();
return result;
}
Here is the interface of that ParentObjectMapper :
/* Hiding imports for brevity */
public interface ParentObjectMapper {
// Get the list children, the list should be a property within the parent object.
ParentObject getChildren();
}
I suppose you execute through a mapper interface and the method would be: ParentObject getChildren(); this explicitly expect a single result because this is not a collection type, then the error you got.
But I'm not telling you should change to List<ParentObject> getChildren(); to avoid this error ... or maybe you should ... for a while, because it would help understanding the issue:
With your code Mybatis creates a new ParentObject for each result row because the parentId is never returned and Mybatis does not assume you have a single parent. Then the query shall return a parentId column and the ParentObjectMap start with <id column="parentId" property="id"/>, so that Mybatis knows how to group children by their parent.
I have a class called WebAsset:
public class WebAsset {
private Long id;
private String url;
private int status;
//more fields that are not relevent
}
I need to be able to show relationships between WebAsset, so I created a table for the relationship and a composite key class.
public class WebAssetReferencePK {
private Long sourceAssetId;
private Long targetAssetId;
}
public class WebAssetReference {
private WebAssetReferencePK wpk;
private Long updateTime;
}
We are forced to use an older version of Hibernate so we need to use xml files instead of annotaions. Here is the mapping for the reference class:
<class name="ca.gc.cra.www.crawler.valueobject.WebAssetReference" table="webassetreference">
<composite-id name="webAssetReferencePK" class="ca.gc.cra.www.crawler.valueobject.WebAssetReferencePK">
<key-property name="sourceAsset" type="java.lang.Long" column="sourceAssetId" />
<key-property name="targetAsset" type="java.lang.Long" column="targetAssetId" />
</composite-id>
<property name="updateTime" type="java.lang.Long" column="updatetime" not-null="true" />
</class>
In the composite key I get what I expect in the database with 2 ids related to each other. But when I try to query with HQL or Criteria it doesn't work since there is no direct relation between the PK class and WebAsset and I need to be able to do a join between WebAsset and WebAssetReference. If I try to change the composite key types from java.lang.Long to WebAsset then hibernate stores the whole object in the WebAssetReference table instead of just the ids.
An example of what I am trying to do is if I have a sourceAssetId I want to return all the targetAssetIds with the same source, but I don't want the ids themselves I want the WebAsset that is the primary key for each targetAssetId.
I have been searching around for the answer but every example I can find are just simple examples that don't relate.
Update 1: With continued searching I finally found the answer. Instead of key-property I need to use key-many-to-one. I haven't tried a join yet but everything else looks right so this should be the answer.
Update 2: Can't get the query to work with HQL. Here is th SQL of what I am trying to do:
select * from webasset as wa join webassetreference as war on war.targetassetid=wa.webasset_id where war.sourceassetid=?
Here is the HQL that is not working:
FROM WebAsset JOIN WebAssetReference WebAssetReference.WebAssetReferencePK.targetAsset=WebAsset WHERE WebAssetReference.WebAssetReferencePK.sourceAsset = :sourceAsset
I get the following error with HQL: ERROR - line 1:89: unexpected token: .
I'll keep trying but I can't seem to figure out the HQL.
I discovered how to do this. In the case I have above it will not work since I have 2 columns joining to the same table. However if I use the same WebAsset class above and instead use this class:
public class TreeNode implements Comparable<TreeNode>{
private String nodeUrl;
private Long id;
private Boolean folder;
private transient WebAsset nodeAsset = null;
}
With this .hbm.xml file:
<class name="ca.gc.cra.www.crawler.valueobject.TreeNode" table="TreeNode">
<id name="id" type="java.lang.Long" column="treenode_id" >
<generator class="identity"/>
</id>
<many-to-one name="nodeAsset" class="ca.gc.cra.www.crawler.valueobject.WebAsset" column="nodeAsset_id" lazy="false" not-null="false" cascade="none" unique="true" />
<property name="folder" type="java.lang.Boolean" column="folder" not-null="true" />
<property name="nodeUrl" length="512" type="java.lang.String" column="nodeUrl" not-null="true" />
<set name="children" table="TreeNode" inverse="false" lazy="true" >
<key column="parentnode_id"/>
<one-to-many class="ca.gc.cra.www.crawler.valueobject.TreeNode" />
</set>
</class>
You can then use this code to retrieve the join:
Session session = HibernateUtil.getSession();
try {
String hql = "FROM TreeNode tn JOIN tn.nodeAsset WHERE tn.id=5";
Query query = session.createQuery(hql);
List result = query.list();
System.out.println("done");
} catch (HibernateException e) {
e.printStackTrace();
throw new Exception("Query failed", e);
} finally {
session.flush();
session.close();
}
Hibernate can then perform the join correctly. The result will be a List containing an Object array for each entry. The Object contains the 2 classes that are part of the join. You have to cast the Object with (Object[]) to access the elements and then cast each on to the appropriate class.
I would recommend against this approach because Hibernate will attempt to load all connected classes as well. With the example above I was getting 1 row from TreeNode yet it generated 19 select statements. I even attempted to set the connected classes to lazy load and it still generated all the selects.
I am running into a problem managing my Hibernate-backed collections. The problem is illustrated in the code below; briefly,
A single session and transaction are started.
All instances of ClassA are loaded and walked to force Hibernate to load all instances of ClassC. At this point all instances of ClassC actually load via lazy fetching.
In the same transaction and session, all instances of ClassB are loaded.
All instances of ClassC are no longer available (the containing collections are empty) and do not lazy load if requested.
What's the best way to load up the data sets needed and keep them in memory?
Notes:
The project is in rapid-prototyping mode so I am using a single session and single
transaction to load up two big chunks of the application's data. This is also a desktop application so the use of a single session and transaction may not even be a problem in the long run if the code were working.
I set up ehcache and the debugger showing that Hibernate found the ehcache config file. The cache is set such that
maxElementsInMemory="5000000"
eternal="true"
the timeouts are set to 20 mins, even though eternal is set true, just to be sure the session isn't timing out.
The data set size is not particularly large, about 100k records.
The Hibernate 3.0 module packaged with NetBeans was use to create the class templates from a data model.
The mapping file looks roughly like this:
<hibernate-mapping>
<class catalog="myCatalog" name="ClassA" table="classA">
<id ... </id>
<set inverse="true" name="classCs" sort="natural">
<key>
<column length="12" name="mykey" not-null="true"/>
</key>
<one-to-many class="ClassC"/>
</set>
</class>
</hibernate-mapping>
Class definitions:
#Entity
#Table(name = "classA", catalog = "myCatalog")
public class ClassA implements java.io.Serializable {
private SortedSet<ClassC> classCs = new TreeSet<ClassC>();
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "ClassA")
public SortedSet<ClassC> getClassCs() {
return this.classCs;
}
}
#Entity
#Table(name = "classB", catalog = "myCatalog")
public class ClassB implements java.io.Serializable {
// ... It is possible to walk collections in this class to reach some instances of classA.
}
public class ClassC implements java.io.Serializable {
// ... contains no collections
}
Manifestation of problem:
// in Hibernate Util
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
public static void main(String[] args) {
Application.session = HibernateUtil.getSessionFactory().openSession();
Application.tx = session.beginTransaction();
// Load data set 'A' and force collections to load
List<ClassA> listClassA = new ArrayList<ClassA>();
Query q = Application.session.createQuery("from ClassA as a").setReadOnly(true);
Iterator<ClassA> iterator = q.list().iterator();
while (iterator.hasNext()) {
ClassA ca = (ClassA)iterator.next();
// force member collection to load -- at present this is necessary even though FetchType is EAGER
ca.getClassCs();
listClassA.add(ca);
}
// The collections of classCs are in are in memory here
for(ClassA a : listClassA){
log.info(a.getId() + "-" + a.getClassCs().size());
}
// Load data set 'B'
List<ClassB> listClassB = new ArrayList<ClassB>();
String sq = "from classB as b where ...";
Query q = Application.session.createQuery(sq);
listClassB.addAll(q.list());
// The collections of classCs are NOT in memory and touching collections does not force reload
// The collections exist but now all have size zero
for(ClassA a : listClassA){
log.info(a.getId() + "-" + a.getClassCs().size());
}
return;
}
I turns out that Hibernate can optionally flush the session cache before each query. One of the settings to control the session cache is session.setFlushMode(). In Hibernate 3.2.5, setting flush mode to:
FlushMode.COMMIT or FlushMode.MANUAL
achieves the desired result. I found this while reading "Hibernate in Action".
I know that deleting orphaned child objects is a common question on SO and a common problem for people new to Hibernate, and that the fairly standard answer is to ensure that you have some variation of cascade=all,delete-orphan or cascade=all-delete-orphan on the child collection.
I'd like to be able to have Hibernate detect that child collection has been emptied/removed from the parent object, and have the rows in the child table deleted from the database when the parent object is updated. For example:
Parent parent = session.get(...);
parent.getChildren().clear();
session.update(parent);
My current mapping for the Parent class looks like:
<bag name="children" cascade="all-delete-orphan">
<key column="parent_id" foreign-key="fk_parent_id"/>
<one-to-many class="Child"/>
</bag>
This works fine for me when updating an attached object, but I have a use case in which we'd like to be able to take a detached object (which has been sent to our API method by a remote client over HTTP/JSON), and pass it directly to the Hibernate Session - to allow clients to be able to manipulate the parent object in whichever way they like and have the changes persisted.
When calling session.update(parent) on my detached object, the rows in the child table are orphaned (the FK column is set to null) but not deleted. Note that when I'm calling session.update(), this is the first time the Hibernate Session is seeing this object instance - I am not re-attaching or merging the object with the Session in any other way. I'm relying on the client to pass objects whose identifiers correspond to actual objects in the database. For example, the logic in my API service method is something like this:
String jsonString = request.getParameter(...);
Parent parent = deserialize(jsonString);
session.update(parent);
Is it possible for Hibernate to detect orphaned children collections in detached parent objects when passed to session.update(parent)? Or am I mis-using the detached object in some way?
My hope was that I could avoid any sort of complex interactions with Hibernate to persist changes to a detached instance. My API method has no need to further modify the detached object after the call to session.update(parent), this method is merely responsible for persisting changes made by remote client applications.
Your mapping (simplified)
<?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 package="br.com._3988215.model.domain">
<class name="Parent" table="PARENT">
<id name="id">
<generator class="native"/>
</id>
<bag cascade="all,delete-orphan" name="childList">
<key column="PARENT_ID" not-null="false"/>
<one-to-many class="Child"/>
</bag>
</class>
<class name="Child" table="CHILD">
<id name="id" column="CHILD_ID">
<generator class="native"/>
</id>
</class>
</hibernate-mapping>
produces
PARENT
ID
CHILD
CHILD_ID
PARENT_ID
According what you said
I would like to be able to have Hibernate detect that child collection has been removed from the parent object, and have the rows in the child table deleted from the database when the parent object is updated
Something like
Parent parent = session.get(...);
parent.getChildren().clear();
session.update(parent);
You said it works fine because you have an attached Parent instance
Now let's see the following one (Notice Assert.assertNull(second))
public class WhatYouWantTest {
private static SessionFactory sessionFactory;
private Serializable parentId;
private Serializable firstId;
private Serializable secondId;
#BeforeClass
public static void setUpClass() {
Configuration c = new Configuration();
c.addResource("mapping.hbm.3988215.xml");
sessionFactory = c.configure().buildSessionFactory();
}
#Before
public void setUp() throws Exception {
Parent parent = new Parent();
Child first = new Child();
Child second = new Child();
Session session = sessionFactory.openSession();
session.beginTransaction();
parentId = session.save(parent);
firstId = session.save(first);
secondId = session.save(second);
parent.getChildList().add(first);
parent.getChildList().add(second);
session.getTransaction().commit();
session.close();
}
#Test
public void removed_second_from_parent_remove_second_from_database() {
Parent parent = new Parent();
parent.setId((Integer) parentId);
Child first = new Child();
first.setId((Integer) firstId);
/**
* It simulates the second one has been removed
*/
parent.getChildList().add(first);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.update(parent);
session.getTransaction().commit();
session.close();
session = sessionFactory.openSession();
session.beginTransaction();
Child second = (Child) session.get(Child.class, secondId);
Assert.assertNull(second);
session.getTransaction().commit();
session.close();
}
}
Unfortunately, the test do not pass. What you can do ???
Enable a long-running conversation
Hibernate reference says
Extended (or Long) Session - The Hibernate Session may be disconnected from the underlying JDBC connection after the database transaction has been committed, and reconnected when a new client request occurs. This pattern is known as session-per-conversation and makes even reattachment unnecessary. Automatic versioning is used to isolate concurrent modifications and the Session is usually not allowed to be flushed automatically, but explicitely.
disclaimer: i do not have any scenario which uses long running conversation. Java EE Stateful session beans support long running conversation. But its support is for JPA (not Hibernate)
Or you can create an alternative mapping which enables your Child as composite elements. Because its lifecycle depends on the parent object, you can rely on composite elements to get what you want
Create a class named AlternativeParent which extends Parent
public class AlternativeParent extends Parent {}
Now its mapping (Notice Child as composite element instead of plain #Entity)
<class name="AlternativeParent" table="PARENT">
<id name="id">
<generator class="native"/>
</id>
<bag name="childList" table="CHILD">
<key column="PARENT_ID" not-null="false"/>
<composite-element class="Child">
<property column="CHILD_ID" name="id"/>
</composite-element>
</bag>
</class>
Now implement a convenient equals method in the Child class
public boolean equals(Object o) {
if (!(o instanceof Child))
return false;
Child other = (Child) o;
// identity equality
// Used by composite elements
if(getId() != null) {
return new EqualsBuilder()
.append(getId(), other.getId())
.isEquals();
} else {
// object equality
}
}
If i refactor the test case shown above (Now by using AlternativeParent instead)
#Test
public void removed_second_from_parent_remove_second_from_database() {
AlternativeParent parent = new AlternativeParent();
parent.setId((Integer) parentId);
Child first = new Child();
first.setId((Integer) firstId);
/**
* It simulates the second one has been removed
*/
parent.getChildList().add(first);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.update(parent);
session.getTransaction().commit();
session.close();
session = sessionFactory.openSession();
session.beginTransaction();
Child second = (Child) session.get(Child.class, secondId);
Assert.assertNull(second);
session.getTransaction().commit();
session.close();
}
I see a green bar
i think,when using detached session, you might face problem, with collections. i will suggest you to first load the entity with collection, and then update that entity with the changes, that will help.