Search code examples
c#nhibernatestored-proceduresfluent-nhibernatefluent-nhibernate-mapping

Nhibernate: invoke stored procedure with CreateSqlQuery using already defined mapping


I Invoke a stored procedure using ISession.CreateSQLQuery.

Then I use

SetResultTransformer(new AliasToBeanResultTransformer(typeof(Article))).List<Article>().ToList()

The problem with this approach is that the AliasToBeanResultTransformer only maps the Article table to the Article class one to one.

public class Article : Entity
{
    public virtual string Description { get; set; }
}

public class Entity
{
    public virtual int Id { get; set; }
}

public class ArticleRepository : Repository<Article>, IArticleRepository
{
    private ISession _session;

    public ArticleRepository(ISession session) : base(session)
    {
        _session = session;
    }

    public List<Article> GetByDescription(string description)
    {
        return _session
            .CreateSQLQuery("EXEC ArticlesByDescription :Description")
            .SetString("Description", description)
            .SetResultTransformer(new AliasToBeanResultTransformer(typeof(Article)))
            .List<Article>().ToList();
    }
}

But my primary key on my Article table is called ArticleId, so that the AliasToBeanResultTransformer throws an exception.

Could not find a setter for property 'ArticleId' in class 'Core.DomainModels.Article'

Is there a way of reusing the FluentNhibernateMapping when using CreateSqlQuery?

EDIT:

The Nhibernate Documentation describes how you can use an already mapped entity with hbm files.

<sql-query name="GetProductsByCategoryId">
   <return class="Product" />
   exec dbo.GetProductsByCategoryId :CategoryId
</sql-query>

I really ask myself why is it not possible to do this just by code?!


Solution

  • It seems not possible to use ISession.CreateSQLQuery and get a mapped entity back from the ISession.

    What I do for now is using hbm files and FluentNhibernate mappings together.

    Hbm:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Core" namespace="Core.DomainModels">
      <sql-query name="ArticlesByDescription">
        <return class="Article" />
        EXEC ArticlesByDescription :Description
      </sql-query>
    </hibernate-mapping>
    

    FluentNhibernate:

    public class ArticleMapping : ClassMap<Article>
    {
        public ArticleMapping()
        {
            Id(x => x.ArticleId).GeneratedBy.Identity();
            Map(x => x.Description).UniqueKey("Article_Description_Unique");
        }
    }
    

    Configuration:

    public class ConfigurationFactory
    {
        const string Database = "";
        const string Server = "";
    
        public static Configuration Build()
        {           
            return Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008.ConnectionString(
                    c => c.Database(Database).TrustedConnection().Server(Server)))
                .Mappings(m =>
                {
                    m.FluentMappings.AddFromAssemblyOf<ArticleMapping>();
                    m.HbmMappings.AddFromAssemblyOf<ArticleMapping>();
                })
                //.ExposeConfiguration(c => new SchemaExport(c).Execute(true, true, false))
                .BuildConfiguration();
        }
    }
    

    Repository:

    public class ArticleRepository : Repository<Article>, IArticleRepository
    {
        private ISession _session;
    
        public ArticleRepository(ISession session) : base(session)
        {
            _session = session;
        }
    
        public List<Article> GetByDescription(string description)
        {
            return _session
                .GetNamedQuery("ArticlesByDescription")
                .SetString("Description", description)
                .List<Article>().ToList();
        }
    }