0
votes

I am trying to figure out what I thought was just a simple one to many mapping using fluent Nhibernate. I hoping someone can point me to the right directory to achieve this one to many relations I have an articles table and a categories table Many Articles can only belong to one Category Now my Categores table has 4 Categories and Articles has one article associated with cateory1

here is my setup.

using FluentNHibernate.Mapping;
using System.Collections;
using System.Collections.Generic;

namespace FluentMapping
{
    public class Article
    {

        public virtual int Id { get; private set; }
        public virtual string Title { get; set; }
        public virtual Category Category{get;set;}
    }
    public class Category
    {
        public virtual int Id { get; private set; }
        public virtual string Description { get; set; }
        public virtual IList<Article> Articles { get; set; }
        public Category()
        {
            Articles=new List<Article>();
        }

        public virtual void AddArticle(Article article)
        {
            article.Category = this;
            Articles.Add(article);
        }
        public virtual void RemoveArticle(Article article)
        {
            Articles.Remove(article);
        }

    }
    public class ArticleMap:ClassMap<Article>
    {
        public ArticleMap()
        {
            Table("Articles");
            Id(x => x.Id).GeneratedBy.Identity();
            Map(x => x.Title);
            References(x => x.Category).Column("CategoryId").LazyLoad();

        }
        public class CategoryMap:ClassMap<Category>
        {
            public CategoryMap()
            {
                Table("Categories");
                Id(x => x.Id).GeneratedBy.Identity();
                Map(x => x.Description);
                HasMany(x => x.Articles).KeyColumn("CategoryId").Fetch.Join();
            }
        }
    }
}

if I run this test

[Fact]
    public void Can_Get_Categories()
    {
        using (var session = SessionManager.Instance.Current)
        {
            using (var transaction = session.BeginTransaction())
            {
                var categories = session.CreateCriteria(typeof(Category))
                              //.CreateCriteria("Articles").Add(NHibernate.Criterion.Restrictions.EqProperty("Category", "Id"))                                
                .AddOrder(Order.Asc("Description"))
                              .List<Category>();

            }
        }
    }

I am getting 7 Categories due to Left outer join used by Nhibernate any idea what I am doing wrong in here? Thanks [Solution] After a couple of hours reading nhibernate docs I here is what I came up with

var criteria = session.CreateCriteria(typeof (Category));
                    criteria.AddOrder(Order.Asc("Description"));
                    criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());
var cats1 = criteria.List<Category>();

Using Nhibernate linq provider

 var linq = session.Linq<Category>();
                    linq.QueryOptions.RegisterCustomAction(c => c.SetResultTransformer(new DistinctRootEntityResultTransformer()));
                    var cats2 = linq.ToList();
2

2 Answers

0
votes

I don't really know what's the problem, because I don't know how you save the categories, but it might be caused by using the wrong cascade setting in the mapping?

0
votes

Using Join on a HasMany is unusual; it's typically used on References, the many side of a one-to-many relationship. Instead of the solution you came up with, you should lazy load the collection or use Fetch.Select. Both will cause NH to issue two selects, one to load the Category and another to load its associated Articles.

Addendum:

The error you're getting is pretty straight-forward: the collection can't be loaded because the ISession that was used to load the parent is out of scope (or its connection was closed). Setting the fetch mode to Select will resolve this (I think, I haven't tried it). So your collection mapping would be:

HasMany(x => x.Articles).KeyColumn("CategoryId").Fetch.Select();

If you can keep the ISession open I would recommend lazy loading:

HasMany(x => x.Articles).KeyColumn("CategoryId").LazyLoad();

It's unusual to use Join on a collection mapping due to the problem you ran into. Issuing a join from the one side will return a parent object for each object in the collection, just as it would in SQL.