These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: deletion of composite-elements
PostPosted: Wed Dec 20, 2006 1:52 pm 
Newbie

Joined: Mon Jul 18, 2005 7:45 am
Posts: 16
I'm trying to map a simple 1-2-m collection using the <composite-element> element. I've created a simple example (see below) to try to see what is going on.

I can create a parent and add 2 child items and these are persisted correctly. However if I try to then remove a single item, NHibernate deleted both items - SQL output pasted below.

I suspect this has something to do with the 'identity' of the child items since there is no explicit key for these items, but I'm struggling to find any good examples of this in practice.

Can anybody explain what is going on here? An example would be even better.


Mapping file:

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="Examples.CompositeElement.CompositeElementParent, Examples"
    table="CompositeElementParent" lazy="false">
   
    <id name="Id" column="ParentID">
      <generator class="identity" />
    </id>
   
    <property name="Name" column="Name" />

    <list name="Children" table="CompositeElementChild" access="nosetter.camelcase-underscore">
      <key column="ParentID" />
      <index column="[Index]" />
      <composite-element class="Examples.CompositeElement.CompositeElementChild, Examples">
        <property name="Name" column="Name"/>
      </composite-element>
    </list>

  </class>
</hibernate-mapping>



Database:

Code:
CREATE TABLE [dbo].[CompositeElementParent](
   [ParentID] [int] IDENTITY(1,1) NOT NULL,
   [Name] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_CompositeElementParent] PRIMARY KEY CLUSTERED
(
   [ParentID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[CompositeElementChild](
   [ChildID] [int] IDENTITY(1,1) NOT NULL,
   [ParentID] [int] NOT NULL,
   [Index] [int] NOT NULL,
   [Name] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_CompositeElementChild] PRIMARY KEY CLUSTERED
(
   [ChildID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE [dbo].[CompositeElementChild]  WITH CHECK ADD  CONSTRAINT [FK_CompositeElementChild_CompositeElementParent] FOREIGN KEY([ParentID])
REFERENCES [dbo].[CompositeElementParent] ([ParentID])


SQL Output:

Code:
NHibernate: INSERT INTO NHibernateMappingExamples.dbo.CompositeElementParent (Name) VALUES (@p0); select SCOPE_IDENTITY()
@p0 = 'Parent'
NHibernate: INSERT INTO NHibernateMappingExamples.dbo.CompositeElementChild (ParentID, [Index], Name) VALUES (@p0, @p1, @p2)
@p0 = '22'
@p1 = '0'
@p2 = 'Child 2'
NHibernate: INSERT INTO NHibernateMappingExamples.dbo.CompositeElementChild (ParentID, [Index], Name) VALUES (@p0, @p1, @p2)
@p0 = '22'
@p1 = '1'
@p2 = ''
NHibernate: SELECT compositee0_.ParentID as ParentID0_, compositee0_.Name as Name0_0_ FROM NHibernateMappingExamples.dbo.CompositeElementParent compositee0_ WHERE compositee0_.ParentID=@p0
@p0 = '22'
NHibernate: SELECT children0_.ParentID as ParentID__0_, children0_.Name as Name0_, children0_.[Index] as column3___0_ FROM NHibernateMappingExamples.dbo.CompositeElementChild children0_ WHERE children0_.ParentID=@p0
@p0 = '22'
NHibernate: DELETE FROM NHibernateMappingExamples.dbo.CompositeElementChild WHERE ParentID = @p0 AND [Index] = @p1
@p0 = '22'
@p1 = '1'
NHibernate: DELETE FROM NHibernateMappingExamples.dbo.CompositeElementChild WHERE ParentID = @p0 AND [Index] = @p1
@p0 = '22'
@p1 = '0'
NHibernate: SELECT compositee0_.ParentID as ParentID0_, compositee0_.Name as Name0_0_ FROM NHibernateMappingExamples.dbo.CompositeElementParent compositee0_ WHERE compositee0_.ParentID=@p0
@p0 = '22'
NHibernate: SELECT children0_.ParentID as ParentID__0_, children0_.Name as Name0_, children0_.[Index] as column3___0_ FROM NHibernateMappingExamples.dbo.CompositeElementChild children0_ WHERE children0_.ParentID=@p0
@p0 = '22'


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 20, 2006 4:45 pm 
Newbie

Joined: Wed Dec 20, 2006 9:00 am
Posts: 10
Location: Brazil (GMT-3)
I don't think the absence of an identity is your problem since NHibernate Reference Manual doesn't state that it is necessary. Any way, it states in section 16.5 that you may have a surrogate primary key with <idbag> if you wish.
Are you sure it isn't the way you are manipulating your collection which is causing the problem?

Luis


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 21, 2006 6:01 am 
Newbie

Joined: Mon Jul 18, 2005 7:45 am
Posts: 16
This is my (annotated) test.

Code:

        [TestMethod]
        public void CanRemoveCompositeElements()
        {
            CompositeElementParent parent = GetInstanceWithChildren();

            ISession session = NHibernateSessionManager.GetSession();

            Console.WriteLine("Persist instance and Flush.");
            session.SaveOrUpdate(parent);
            session.Flush();
            Console.WriteLine("Child Count: " + parent.Children.Count);

            Console.WriteLine("Evict and Reload instance.");
            session.Evict(parent);
            CompositeElementParent reloadedParent = LoadParent(parent.Id);
            Console.WriteLine("Child Count: " + reloadedParent.Children.Count);

            Console.WriteLine("Remove the first child.");
            reloadedParent.Children.Remove(reloadedParent.Children[0]);
            Console.WriteLine("Child Count: " + reloadedParent.Children.Count);

            Console.WriteLine("Flush Changes");
            session.Flush();
            Console.WriteLine("Child Count: " + reloadedParent.Children.Count);

            Console.WriteLine("Evict and Reload instance.");
            session.Evict(reloadedParent);
            reloadedParent = LoadParent(parent.Id);
            Console.WriteLine("Child Count: " + reloadedParent.Children.Count);

            Assert.AreEqual(1, reloadedParent.Children.Count, "Incorrect no. of Children");
        }

        private CompositeElementParent GetInstanceWithChildren()
        {
            CompositeElementParent parent = new CompositeElementParent();
            parent.Name = "Parent";

            CompositeElementChild child1 = new CompositeElementChild();
            child1.Name = "Child 1";
            parent.Children.Add(child1);

            CompositeElementChild child2 = new CompositeElementChild();
            child1.Name = "Child 2";
            parent.Children.Add(child2);

            return parent;
        }

        private CompositeElementParent LoadParent(int parentId)
        {
            ISession session = NHibernateSessionManager.GetSession();

            CompositeElementParent reloadedParent =
                (CompositeElementParent)session.Get(typeof(CompositeElementParent), parentId);

            return reloadedParent;
        }


And this is the Console output:

Code:
Persist instance and Flush.
NHibernate: INSERT INTO NHibernateMappingExamples.dbo.CompositeElementParent (Name) VALUES (@p0); select SCOPE_IDENTITY()
@p0 = 'Parent'
NHibernate: INSERT INTO NHibernateMappingExamples.dbo.CompositeElementChild (ParentID, [Index], Name) VALUES (@p0, @p1, @p2)
@p0 = '29'
@p1 = '0'
@p2 = 'Child 2'
NHibernate: INSERT INTO NHibernateMappingExamples.dbo.CompositeElementChild (ParentID, [Index], Name) VALUES (@p0, @p1, @p2)
@p0 = '29'
@p1 = '1'
@p2 = ''
Child Count: 2
Evict and Reload instance.
NHibernate: SELECT compositee0_.ParentID as ParentID0_, compositee0_.Name as Name0_0_ FROM NHibernateMappingExamples.dbo.CompositeElementParent compositee0_ WHERE compositee0_.ParentID=@p0
@p0 = '29'
NHibernate: SELECT children0_.ParentID as ParentID__0_, children0_.Name as Name0_, children0_.[Index] as column3___0_ FROM NHibernateMappingExamples.dbo.CompositeElementChild children0_ WHERE children0_.ParentID=@p0
@p0 = '29'
Child Count: 2
Remove the first child.
Child Count: 1
Flush Changes
NHibernate: DELETE FROM NHibernateMappingExamples.dbo.CompositeElementChild WHERE ParentID = @p0 AND [Index] = @p1
@p0 = '29'
@p1 = '1'
NHibernate: DELETE FROM NHibernateMappingExamples.dbo.CompositeElementChild WHERE ParentID = @p0 AND [Index] = @p1
@p0 = '29'
@p1 = '0'
Child Count: 1
Evict and Reload instance.
NHibernate: SELECT compositee0_.ParentID as ParentID0_, compositee0_.Name as Name0_0_ FROM NHibernateMappingExamples.dbo.CompositeElementParent compositee0_ WHERE compositee0_.ParentID=@p0
@p0 = '29'
NHibernate: SELECT children0_.ParentID as ParentID__0_, children0_.Name as Name0_, children0_.[Index] as column3___0_ FROM NHibernateMappingExamples.dbo.CompositeElementChild children0_ WHERE children0_.ParentID=@p0
@p0 = '29'
Child Count: 0


It seems very strange to me that calling Flush causes 2 deletes to execute but the in-session collection still contains a single item.

[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 21, 2006 7:27 am 
Newbie

Joined: Mon Jul 18, 2005 7:45 am
Posts: 16
Interestingly, the test passes if I remove the second (and last) item in the collection - e.g.

Code:
reloadedParent.Children.Remove(reloadedParent.Children[1]);


instead of

Code:
reloadedParent.Children.Remove(reloadedParent.Children[0]);


Any ideas what is going on here?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 21, 2006 9:08 am 
Newbie

Joined: Wed Dec 20, 2006 9:00 am
Posts: 10
Location: Brazil (GMT-3)
sthorogood wrote:
Interestingly, the test passes if I remove the second (and last) item in the collection - e.g.

Code:
reloadedParent.Children.Remove(reloadedParent.Children[1]);


instead of

Code:
reloadedParent.Children.Remove(reloadedParent.Children[0]);


Any ideas what is going on here?


Not sure, but I'd suggest that you should open and close a transaction between "Evicts".

If doesn't work, could you try to close the sessions before evicting as well?

BTW, you assign "Child 2" to child1.Name in function GetInstanceWithChildren, resulting that child2 gets no name.

Luis


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 21, 2006 1:35 pm 
Newbie

Joined: Mon Jul 18, 2005 7:45 am
Posts: 16
Hi - bizzare but true - the problem was related to the null value for the Child item Name property due to my error as you pointed out.

All seems to work now...

Thanks very much!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.