1

In my object graph, VendorServiceRateChange has a lazy loaded property IList<VendorService> VendorServiceList and the VendorService has a lazy loaded property IList<ClientService>.

When I run the following code I get a Cartesian product between my VendorServiceList and my ClientServiceList.

queueList = session
    .CreateCriteria<VendorRateChange>()
    .Add(Restrictions.IsNull("ProcessedDate"))
    .Add(Restrictions.Le("EffectiveDate", DateTime.Now))
    .SetFetchMode("VendorServiceList", FetchMode.Join)
    .SetFetchMode("VendorServiceList.Vendor", FetchMode.Join)
    .SetFetchMode("VendorServiceList.CityService", FetchMode.Join)
    .SetFetchMode("VendorServiceList.ClientServices", FetchMode.Join)
    .SetResultTransformer(new DistinctRootEntityResultTransformer())
    .AddOrder(new Order("Audit.CreatedDate", true))
    .List<VendorRateChange>();

Is there a way to structure this query using Criteria or DetachedCriteria that would not result in a Cartesian product as my VendorServiceList? I do not want to have to resort to commenting out the fetch on "VendorServiceList.ClientServices" and looping through with an Initialize call after the initial query has come back.

Thanks in advance.

rie819
  • 1,249
  • 12
  • 19

2 Answers2

3

Are you sure it is a cartesian product, or you just receive "duplicated" rows in the retuned list ? If so, before .List(), try to call .SetResultTransformer(Transformers.DistinctRootEntity), because by eager fetching the associated collection you receive a list containing duplicates of the same entity.

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115
  • assuming it's the same as .SetResultTransformer(new DistinctRootEntityResultTransformer()) then yes, I'm already calling it. It may just be duplicate rows, but it's not the root that's getting duplicated. I'm getting extra rows at the VendorServiceList level and have no clue on how to purge them. – rie819 Sep 19 '11 at 19:57
  • Recent versions of Hibernate: .setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE); – Will Shaver Apr 30 '12 at 22:51
1

You can have a single FetchMode.Join before you start creating cartesian products. What if you switch others to FetchMode.Select or something else?

Shane Courtrille
  • 13,960
  • 22
  • 76
  • 113
  • Doesn't FetchMode.Select make those properties Lazy loaded? My goal is to populate all the values with one trip to the DB. – rie819 Sep 19 '11 at 20:16
  • 1
    FetchMode.Select uses another Select query to populate that data instead of using a join. – Cole W Sep 19 '11 at 20:23
  • @Cole W Thanks, I just assumed that Join meant eager and Select meant lazy. – rie819 Sep 19 '11 at 20:29
  • 2
    @rie819, you should check out this post here though for loading object graphs. http://stackoverflow.com/questions/5266180/fighting-cartesian-product-x-join-when-using-nhibernate-3-0-0 – Cole W Sep 19 '11 at 20:32