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.  [ 3 posts ] 
Author Message
 Post subject: Newby Eager Fetch Question
PostPosted: Sat Feb 17, 2007 9:06 pm 
Newbie

Joined: Sat Sep 23, 2006 5:23 pm
Posts: 3
This is probably a simple mapping problem but I can't see what I'm doing wrong. Everything works as expected except the query or criteria used below return duplicate OneToManyBag objects. One for each child object.

If I replace the bag with a set this doesn't happen. If I don't eagerly fetch this doesn't happen.

I thought this might be similar http://forum.hibernate.org/viewtopic.php?t=960001 but it seems that is about duplicates with multiple child collections.

How do I return a list with a single instance of each parent object?

Thanks

Hibernate version:NHibernate-1.2.0.Beta3

Mapping documents:

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="NHibernateTests" assembly="NHibernateTests">
 
  <class name="OneToManyBag" table="MANY_TO_MANY1" lazy="true">
    <id name="Id">
      <column name="Id" />
      <generator class="sequence">
        <param name="sequence">MANY_TO_MANY1_SEQ</param>
      </generator>
    </id>

    <property name="Name" column="NAME" />

    <bag name="OneToManyDetails" inverse="false" cascade="all-delete-orphan">
      <key column="ONE_TO_MANY_ID" />
      <one-to-many class="OneToManyDetail"/>
    </bag>
  </class>

  <class name="OneToManyDetail" table="ONE_TO_MANY_DETAIL">
    <id name="Id">
      <column name="Id" />
      <generator class="sequence">
        <param name="sequence">ONE_TO_MANY_DETAIL_SEQ</param>
      </generator>
    </id>

    <property name="DetailName" column="NAME" />
  </class>

</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():

Code:
            IQuery query = session.CreateQuery("From OneToManyBag parent Left Join fetch parent.OneToManyDetails");
            IList<OneToManyBag> list = query.List<OneToManyBag>();

or

Code:
            ICriteria crit = session.CreateCriteria(typeof(OneToManyBag)).SetFetchMode("OneToManyDetails", FetchMode.Eager);
            IList<OneToManyBag> list = crit.List<OneToManyBag>();


objects

Code:
using System;
using System.Collections.Generic;
using System.Text;

namespace NHibernateTests
{
    public class OneToManyBag
    {
        public OneToManyBag()
        {
        }

        private int id;
        public virtual int Id
        {
            get { return id; }
            set { id = value; }
        }

        private string name;
        public virtual string Name
        {
            get { return name; }
            set { name = value; }
        }

        private IList<OneToManyDetail> oneToManyDetails = new List<OneToManyDetail>();
        public virtual IList<OneToManyDetail> OneToManyDetails
        {
            get { return oneToManyDetails; }
            set { oneToManyDetails = value; }
        }
   
    }
}

using System;
using System.Collections.Generic;
using System.Text;

namespace NHibernateTests
{
    public class OneToManyDetail
    {
        public OneToManyDetail()
        {
        }

        private int id;
        public virtual int Id
        {
            get { return id; }
            set { id = value; }
        }

        private string detailName;
        public virtual string DetailName
        {
            get { return detailName; }
            set { detailName = value; }
        }
   
    }
}


Name and version of the database you are using:

Oracle 9i

The generated SQL (show_sql=true):

SELECT this_.Id as Id0_1_, this_.NAME as NAME0_1_, onetomanyd2_.ONE_TO_MANY_ID as ONE3___3_, onetomanyd2_.Id as Id3_, onetomanyd2_.Id as Id1_0_, onetomanyd2_.NAME as NAME1_0_ FROM MANY_TO_MANY1 this_ left outer join ONE_TO_MANY_DETAIL onetomanyd2_ on this_.Id=onetomanyd2_.ONE_TO_MANY_ID


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 10, 2007 7:27 pm 
Newbie

Joined: Mon Aug 21, 2006 9:47 am
Posts: 12
I have the same problem. Im using Criteria to query all the Clients and the clients groups that match the criteria set.

Im using NHibernate 1.2.0 CR1

Code:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns="urn:nhibernate-mapping-2.2" default-cascade="save-update">
   <class name="Vita.Pesa.Domain.BusinessInfo, Vita.Pesa" lazy="true" table="BusinessInfo">

      <id name="Id" column="Id" type="Int32" unsaved-value="0">
         <generator class="identity" />
      </id>
      <property
         name="Name"
         type="String"
         column="Name"
         length="200"
         not-null="true" />
   </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns="urn:nhibernate-mapping-2.2" default-cascade="save-update">
   <joined-subclass
         name="Vita.Pesa.Domain.Client, Vita.Pesa"
         lazy="true"
         extends="Vita.Pesa.Domain.BusinessInfo, Vita.Pesa"
         table="Client">
      
      <key column="BusinessInfoId" />
      
      <bag name="ClientGroups" inverse="true" cascade="all-delete-orphan">
         <key column="ClientId" />
         <one-to-many class="Vita.Pesa.Domain.ClientGroup, Vita.Pesa" />
      </bag>
   </joined-subclass>
</hibernate-mapping>


namespace Vita.Pesa.Domain {
   /// <summary>
   ///   Client
   /// </summary>
   [Serializable]
   [b]public class Client : BusinessInfo [/b]{

      private IList<ClientGroup> _clientGroups;
   

      /// <summary>
      /// Gets the client groups.
      /// </summary>
      /// <value>The client groups.</value>
      public virtual IList<ClientGroup> ClientGroups
      {
         get { return _clientGroups; }
         set { if (_clientGroups != value) _clientGroups = value; }
      }

      
    }
}


namespace Vita.Pesa.Domain {
   /// <summary>
   /// Business Info
   /// </summary>
   [b]public class BusinessInfo [/b]{

      private int _id;
      private string _name;
      

      /// <summary>
      /// Gets or sets the id.
      /// </summary>
      /// <value>The id.</value>
      public virtual int Id {
         get { return _id; }
         set { if (_id != value) _id = value; }
      }

      /// <summary>
      /// Gets or sets the name.
      /// </summary>
      /// <value>The name.</value>
      public virtual string Name {
         get { return _name; }
         set {
            if (String.IsNullOrEmpty(value)) {
               throw new PesaArgumentException(Errors.BusinessNameNull);
            }
            else {
               if (value.Length > 200)
                  throw new PesaArgumentException(Errors.BusinessNameLength);
            }

            if (_name != value) _name = value;
         }
      }
   }
}

public class [b]ClientGroup [/b]{
}


So i have Tables like this:

BusinessInfo
Id int
Name nvarchar(200)


Client
BusinessInfoId int (Id from BusinessInfo table)


ClientGroup
Id int
ClientId int (BusinessInfoId from Client table)

Now i am doing a query like this:
Code:
int[] clientGroupIds = new int[] {2, 3};
string name = "ClientName";

ICriteria criteria = Repository.Session.CreateCriteria(typeof(Client));

criteria.CreateCriteria("ClientGroups", "ClientGroups", JoinType.LeftOuterJoin);

criteria.Add(
   Expression.And(
         Expression.In("ClientGroups.Id", clientGroupIds),
         Expression.Like("Name", name, MatchMode.Start)
      )
   );


return criteria.List<Client>();


Now in the database there is exactly 1 client with name "ClientName" and two ClientGroups with Id -s 2 and 3.

When i make this query i get back a IList<Client> with two Clients (both the same client with two ClientGroups). (What im saying here is that the List has two Client items, which are exactly the same (ID, name etc)).

My only guess is that there are as many clients in the list as there are ClientGroup objects (and this seems to be the case).

I have tryed other criteria queries, but im still getting the same result.

Query generated by nhibernate.

Code:
SELECT
this_.BusinessInfoId as Id7_1_, this_1_.Name as Name7_1_, clientgrou1_.ClientId as ClientId__3_, clientgrou1_.Id as Id3_
FROM Client this_
inner join BusinessInfo this_1_ on this_.BusinessInfoId=this_1_.Id
left outer join ClientGroup clientgrou1_ on this_.BusinessInfoId=clientgrou1_.ClientId
WHERE (clientgrou1_.Id in (@p0, @p1) and this_1_.Name like @p2); @p0 = '2', @p1 = '3', @p2 = 'ClientName%'


I dont understand why this duplication is happening, its not mappind the data back right.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 12, 2007 10:52 am 
Newbie

Joined: Mon Aug 21, 2006 9:47 am
Posts: 12
If anyone is wondering then this seems to do the trick:

criteria.SetResultTransformer(CriteriaUtil.DistinctRootEntity);


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 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.