0

Environment: NHibernate(3.3.3.4001), FluentNHibernate(1.4.0.0) Below is FluentNHibernate mapping:

public class CustomerMap : ClassMap<Customer>
        {
            public CustomerMap()
            {
                Id(x => x.Id);
                Map(x => x.Name).Not.Nullable();
                HasMany(x => x.Orders)
                    .KeyColumn("CustomerId")
                    .Cascade.All()
                    .LazyLoad(); 
                HasMany(x => x.Cards)
                    .KeyColumn("CustomerId")
                    .Cascade.All()
                    .LazyLoad();
            }
        }
        public class OrderMap:ClassMap<Order>
        {
            public OrderMap()
            {
                Id(x => x.Id);
                Map(x => x.OrderTime).Not.Nullable();
                References<Customer>(x => x.OrderOwner)
                    .LazyLoad().Column("CustomerId");
            }
        }
        public class CardMap:ClassMap<Card>
        {
            public CardMap()
            {
                Id(x => x.Id);
                Map(x => x.CardCode).Not.Nullable();
                References<Customer>(x => x.CardOwner)
                    .LazyLoad().Column("CustomerId");
            }
        }

Entity:

public class Customer
        {
            public virtual int Id { get; set; }
            public virtual string Name { get; set; }
            public virtual IList<Order> Orders { get; set; }
            public virtual IList<Card> Cards { get; set; }
        }
        public class Order
        {
            public virtual int Id { get; set; }
            public virtual DateTime  OrderTime { get; set; }
            public virtual Customer OrderOwner { get; set; }
        }
        public class Card
        {
            public virtual int Id { get; set; }
            public virtual string CardCode { get; set; }
            public virtual Customer CardOwner { get; set; }
        }

Now in my Database, Customer Table

    Id  Name
    1   AAA
    2   BBB

Order Table

    Id  OrderTime           CustomerId
    1   2014-04-20 00:48:52.110 1
    2   2014-04-20 00:48:52.110 2
    3   2014-04-20 00:49:01.403 1
    4   2014-04-20 00:49:01.403 1

Card Table

    Id  CardCode    CustomerId
    1   111 1
    2   111 2
    5   222 1
    6   333 1

When I used Criteria and FetchMode.Join to Fetch data which is lazy, the result will contain duplicate Order and Card belonged to Customer. Such as Customer Id = 1, it contains 9(3×3) Order objects and 9(3×3) Card objects.

                   ISession session = FluentlyNHManager.OpenSession();
               ICriteria customerCriteria = session.CreateCriteria<Customer>()
                                            .SetFetchMode("Orders", FetchMode.Join)
                                            .SetFetchMode("Cards", FetchMode.Join)
                            .SetResultTransformer(Transformers.DistinctRootEntity);
               IList<Customer> customerList = customerCriteria.List<Customer>();

But if I used HQL to get data,it's correct. Customer Id = 1 contains 3 Order objects and 3 Card objects.

                   ISession session = FluentlyNHManager.OpenSession();
               ICriteria customerCriteria = session.CreateCriteria<Customer>(@"from Customer c left join fetch
Orders o left join fetch Cards c");          
               IList<Customer> customerList = customerCriteria.List<Customer>();

What can I code to fix the issue about Criteria? Why it have wrong result?

SeaSonS
  • 1
  • 1
  • 2
  • I think i have mistaked the HQL, the right HQL is below, and the result is same as Criteria : IQuery customerCriteria = session.CreateQuery(@"from Customer c left join fetch c.Orders o left join fetch c.Cards ca"); customerCriteria.SetResultTransformer(Transformers.DistinctRootEntity); IList customerList = customerCriteria.List(); – SeaSonS Apr 24 '14 at 16:06

1 Answers1

0

As mentioned in this interesting reading: Ayende - Eagerly loading entity associations efficiently with NHibernate:

One of the things that seems to pop up frequently is people wanting to load an entity with all of its associations eagerly. That is pretty easy to do when the associations are many-to-one (that is, there is only one of them for each root entity). Example of those would be things like Owner, Site, etc.

...

The problem starts when you try to do the same for multiple collection associations. NHibernate allows you to do so, but the result is probably not what you would initially expect...

There are some common ways, please check:

The detailed how to could be found here:

NOTE: if you have fetched child and other child and... the distinct root transformations won't do the job, because it does it only for one root...

My preferred way is: Create simple query only joining many-to-one references. Let collection to be loaded lazily, using batch-size feature (19.1.5. Using batch fetching)

xml:

// class
<class name="ParentEntity" batch-size="25" lazy="true">
// collection
<bag name="Children" lazy="true" batch-size="25"

fluent:

.BatchSize(25)
Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335