1

I have following class and associated mappings (Fluent NHibernate):

public class Category
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual Category ParentCategory { get; set; }
    public virtual IList<Category> ChildCategories { get; set; }
}

Mappings:

public class CategoryMap : ClassMap<Category>
{
    public CategoryMap()
    {
        Table("Categories");

        Id(x => x.Id).Column("Id").CustomType("Int32").Access.Property()
         .CustomSqlType("int").Not.Nullable().Precision(10)
         .GeneratedBy.Identity();

        Map(x => x.Description).Column("Description").Nullable()
         .Generated.Never().CustomType(typeof (string)).Access
         .Property().Length(250);

        Map(x => x.Name).Not.Nullable().Generated.Never().CustomType("string")
         .Access.Property().Column("Name").Length(50);

        References(x => x.ParentCategory).Column("ParentCategoryId");
        HasMany(x => x.ChildCategories).KeyColumn("ParentCategoryId").Inverse()
         .AsBag().Fetch.Select();
    }
}

I creating two Category object as follows:

var c = new Category
        {
            Name = "Ebooks",
            Description = "Contains awz, mobi, pdf, epub and other 
                electronic books"
        };
var cc = new Category
         {
            Name = "Kindle Books",
            Description = "Contains Kindle ebook reader format books 
                    (awz, mobi)",
            ParentCategory = c
         };
session.SaveOrUpdate(c);
session.SaveOrUpdate(cc);

When I try to access saved objects:

var c = session.Load<Category>(1);
var cc = c.ChildCategories;

c contains the Category object with Id of 1 but its ChildCategories property is null.

What I am doing wrong?

PS:- This is my first experiment with NHibernate and so with Fluent NHibernate.

EDIT:- The following stuff worked. I needed to close the session before opening it again for reading. Otherwise it read just from memory nad as @Holf has pointed out I needed to add Child Category to Category like:

c.ChilCategories.Add(cc);

I just did as follows:

var session = sf.OpenSession();
CreateCategory(session);//ADDED TWO CATEGORIES EBooks, Kindle Ebooks
session.Close();

session = sf.OpenSession();
FetchCategories(session);//READ CATEGORY EBooks AND ASSOCIATED CHILDREN
session.Close();
TheVillageIdiot
  • 40,053
  • 20
  • 133
  • 188

2 Answers2

0

Although you've handled one side of the relationship, by assigning 'c' as the ParentCategory of 'cc', I can't see anywhere that you've done the inverse. I think you'll also need to do

c.ChildCategories.Add(cc);

before doing the SaveOrUpdate.

Holf
  • 5,605
  • 3
  • 42
  • 63
  • I don't think this is important or even if I need to do this as both `ChildCategories` and `ParentCategory` are mapped using same column `ParentCategoryId` in the Map. – TheVillageIdiot May 08 '12 at 03:06
  • It is definitely important. The Map is all about telling nHibernate how to map an object graph to a corresponding database schema. Even with this mapping, nHibernate will still only persist what it is given. If you haven't added the child to the parent collection before persisting, nHibernate will not do this on your behalf. – Holf May 08 '12 at 15:53
0

Can you update your map to the following:

public class CategoryMap : ClassMap<Category>
{
    public CategoryMap()
    {
        Table("Categories");

        Id(x => x.Id).Column("Id").CustomType("Int32").Access.Property()
         .CustomSqlType("int").Not.Nullable().Precision(10)
         .GeneratedBy.Identity();

        Map(x => x.Description).Column("Description").Nullable()
         .Generated.Never().CustomType(typeof (string)).Access
         .Property().Length(250);

        Map(x => x.Name).Not.Nullable().Generated.Never().CustomType("string")
         .Access.Property().Column("Name").Length(50);

        References(x => x.ParentCategory).Column("ParentCategoryId");
        HasMany(x => x.ChildCategories).KeyColumn("ParentCategoryId").Inverse()
         .Cascade.All();
    }
}

Also you cannot be sure that the Id with value 1 refers to the Parent Category, use the LInq provider to load the correct object.

Baz1nga
  • 15,485
  • 3
  • 35
  • 61
  • I will try by modifying my map. But I'm sure about `Id = 1` as there are only two records in table. The one with `Id = 2` is having `ParentCategoryId = 1` – TheVillageIdiot May 08 '12 at 03:04