0

The parent class:

public class Group
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual byte[] Icon { get; set; }
    public virtual IList<Category> Categories { get; set; }
}

The child class:

public class Category
{
    public virtual int Id { get; set; }
    public virtual string Description { get; set; }
    public virtual Group Group { get; set; }
}

The mappings:

public CategoryMapping()
{
    this.Table("[Category]");
    this.Schema("[RSS]");
    this.Id(x => x.Id, e => e.Generator(Generators.Identity));
    this.Property(x => x.Description, e =>e.NotNullable(true));
    this.ManyToOne(x => x.Group, e => e.Column("GroupId"));
}

public GroupMapping()
{
    this.Table("[Group]");
    this.Schema("[RSS]");
    this.Id(x => x.Id, e => e.Generator(Generators.Identity));
    this.Property(x => x.Name, e => e.NotNullable(true));
    this.Property(x => x.Icon, e => e.NotNullable(false));
    this.Bag(x => x.Categories, mapper => mapper.Key(e => e.Column("GroupId")), relation => relation.OneToMany());
    }

The problem is when a try to get the group list

var groupList = session.Query<Group>()
        .Fetch(x => x.Categories)
        .Take(10)
        .ToList();

the groupList above end up with duplicated items, like


  1. Group 1
    • Category A
    • Category B
    • Category C
  2. Group 1
    • Category A
    • Category B
    • Category C
  3. Group 1
    • Category A
    • Category B
    • Category C

And the list should be


  1. Group 1
    • Category A
    • Category B
    • Category C
  2. Group 2
    • Category D
    • Category E
    • Category F

something missing in code ?

Thanks in advance.

xikaovs
  • 1
  • 1

1 Answers1

0

You are getting a cartesian product issue with the query above.

Option 1

I have recently changed my mappings to avoid this by mapping collections as sets instead of bags.

This type of change would require you to define your collections like:

public virtual ISet<Category> Categories { get; set; }

And your mappings would change to (this is a guess as I use FNH and not mapping by code):

this.Set(...)

If you change your mappings to this you must then override the Equals and GetHashCode functions for your entities. I strongly recommend using a base class to do this so you don't have to repeat these functions in every entity you have. Here is a great starting point for this base class:

https://github.com/nhibernate/NHibernate.AspNet.Identity/blob/master/source/NHibernate.AspNet.Identity/DomainModel/EntityWithTypedId.cs

Option 2

You can query the items differently to avoid the cartesian product like described in this article:

Fighting cartesian product (x-join) when using NHibernate 3.0.0

Community
  • 1
  • 1
Cole W
  • 15,123
  • 6
  • 51
  • 85