Need help to properly remove duplicates in NHibernate

Posted by Michael D. Kirkpatrick on Stack Overflow See other posts from Stack Overflow or by Michael D. Kirkpatrick
Published on 2010-06-11T20:49:49Z Indexed on 2010/06/11 20:52 UTC
Read the original article Hit count: 198

Filed under:

Here is the problem I am having. I have a database with over 100 records in it. I am paging through the data to get 9 results at a time. When I added a check to see if items are active, it caused the results to start doubling up.

A little background: "Product" is the actual product line "ProductSkus" are the actual products that exist in the product line When there is more then 1 ProductSku within Product, it causes a duplicate entry to be returned.

See the NHibernate Query below:

result = this.Session.CreateCriteria<Model.Product>()                 
                .Add(Expression.Eq("IsActive", true))
                .AddOrder(new Order("Name", true))
                .SetFirstResult(indexNumber).SetMaxResults(maxNumber)

                // This part of the query duplicates the products
                .CreateAlias("ProductSkus", "ProdSkus", JoinType.InnerJoin)
                .Add(Expression.Eq("ProdSkus.IsActive", true))

                .CreateAlias("ProductToSubcategory", "ProdToSubcat")
                .CreateAlias("ProdToSubcat.ProductSubcategory", "ProdSubcat")
                .Add(Expression.Eq("ProdSubcat.ID", subCatId))

                // This part takes out the duplicate products - Removes too many items...
                // Turns out that with .SetFirstResult(indexNumber).SetMaxResults(maxNumber)
                // it gets 9 records back then the duplicates are removed.  
                // Example: 
                //      Total Records over 100
                //      Max = 9
                //      4 Duplicates removed
                //      Yields 5 records when there should be 9
                // Why???  This line is ran in NHibernate on the data after it has been extracted from the SQL server.
                .SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer())

                .List<Model.Product>();

I added the DistinctRootEntityResultTransformer to clean up the duplicates. The problem is that it pulls 9 records back that contains duplicates. DistinctRootEntityResultTransformer then cleans up the duplicates in the 9 records. I am basically needing a distinct statement to be ran on the SQL server to begin with.

However, distinct on SQL is not going to work since NHibernate by default wants to add every field from every table in the select part of the statement. I am only using the fields that belong to the root table to begin with (Model.Product). If I can tell NHibernate to not add the fields to the joined tables into the select part of the statement along with adding Distinct, it would work.

I use NHibernare Profiler to see the actual query:

SELECT   top 9 this_.ID                          as ID351_3_,
           this_.Name                        as Name351_3_,
           this_.Description                 as Descript3_351_3_,
           this_.IsActive                    as IsActive351_3_,
           this_.ManufacturerID              as Manufact5_351_3_,
           prodskus1_.ID                     as ID373_0_,
           prodskus1_.Description            as Descript2_373_0_,
           prodskus1_.PartNumber             as PartNumber373_0_,
           prodskus1_.Price                  as Price373_0_,
           prodskus1_.IsKit                  as IsKit373_0_,
           prodskus1_.IsActive               as IsActive373_0_,
           prodskus1_.IsFeaturedProduct      as IsFeatur7_373_0_,
           prodskus1_.DateAdded              as DateAdded373_0_,
           prodskus1_.Weight                 as Weight373_0_,
           prodskus1_.TimesViewed            as TimesVi10_373_0_,
           prodskus1_.TimesOrdered           as TimesOr11_373_0_,
           prodskus1_.ProductID              as ProductID373_0_,
           prodskus1_.OverSizedBoxID         as OverSiz13_373_0_,
           prodtosubc2_.ID                   as ID362_1_,
           prodtosubc2_.MasterSubcategory    as MasterSu2_362_1_,
           prodtosubc2_.ProductID            as ProductID362_1_,
           prodtosubc2_.ProductSubcategoryID as ProductS4_362_1_,
           prodsubcat3_.ID                   as ID352_2_,
           prodsubcat3_.Name                 as Name352_2_,
           prodsubcat3_.ProductCategoryID    as ProductC3_352_2_,
           prodsubcat3_.ImageID              as ImageID352_2_,
           prodsubcat3_.TriggerShow          as TriggerS5_352_2_
 FROM     Product this_
     inner join ProductSku prodskus1_
       on this_.ID = prodskus1_.ProductID
          and (prodskus1_.IsActive = 1)
     inner join ProductToSubcategory prodtosubc2_
       on this_.ID = prodtosubc2_.ProductID
     inner join ProductSubcategory prodsubcat3_
       on prodtosubc2_.ProductSubcategoryID = prodsubcat3_.ID
 WHERE    this_.IsActive = 1 /* @p0 */
     and prodskus1_.IsActive = 1 /* @p1 */
     and prodsubcat3_.ID = 3 /* @p2 */
 ORDER BY this_.Name asc

If I hand modify the query and run it directly on the SQL server I get the result set I want (I removed all the extra fields in the select section and added DISTINCT):

SELECT DISTINCT  top 9 this_.ID              as ID351_3_,
           this_.Name                        as Name351_3_,
           this_.Description                 as Descript3_351_3_,
           this_.IsActive                    as IsActive351_3_,
           this_.ManufacturerID              as Manufact5_351_3_,
 FROM     Product this_
     inner join ProductSku prodskus1_
       on this_.ID = prodskus1_.ProductID
          and (prodskus1_.IsActive = 1)
     inner join ProductToSubcategory prodtosubc2_
       on this_.ID = prodtosubc2_.ProductID
     inner join ProductSubcategory prodsubcat3_
       on prodtosubc2_.ProductSubcategoryID = prodsubcat3_.ID
 WHERE    this_.IsActive = 1 /* @p0 */
     and prodskus1_.IsActive = 1 /* @p1 */
     and prodsubcat3_.ID = 3 /* @p2 */
 ORDER BY this_.Name asc

The big question I now must ask is...

What must I change in the NHibernate Query to ultimately get the exact same result?

Thanks in advance.

© Stack Overflow or respective owner

Related posts about nhibernate