Help with HasManyConvention.cs

Just the facts…

This is how the entity is storing the collection:

private IList<Forum> forums = new List<Forum>();

The convention file looks like this:

using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.Instances;
namespace Venue.Data.Mapping.Conventions
{
public class HasManyConvention : IHasManyConvention
{
public void Apply(IOneToManyCollectionInstance instance)
{
instance.Key.Column(instance.EntityType.Name +
“Id”[FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2]);
instance.Access.ReadOnlyPropertyThroughLowerCaseField();
instance.Cascade.All();
instance.Inverse();
}

}
}

[/SIZE][/FONT][/SIZE][/FONT]It generates no error, but simply does not fill.

I finally got it to fill using this:

instance.Key.Column(instance.EntityType.Name + “Id”);
instance.Access.ReadOnlyPropertyThroughCamelCaseField(
CamelCasePrefix[FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2].None);
instance.Cascade.All();
instance.Inverse();

[/SIZE][/FONT][/SIZE][/FONT]But there’s another problem. The following code does not work:

Category c1 = cr.Get(2);
Category c2 = cr.Get(4);
Forum f = c1.FindForum(5);
c1.RemoveForum(
null, f);
cr.SaveOrUpdate(c1);
c2.AddForum(
null[FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2], f);
cr.SaveOrUpdate(c2);

[/SIZE][/FONT][/SIZE][/FONT]When the view returns, sure, it shows where c1 now has only 1 forum attached, and c2 now has 2, but when I close it down and look at the raw data in the db. Nothing has changed. C1 still has both it’s original forums, while C2 has the one.

Guys, this is giving me lots of problems, and a lot more hesitation than I really want. This thing is overly complicated. I just want something I can drag and drop some tables on, make a few changes and run with it.

check if its hiting the database… run sql profiler… or download a trial of nhprof.
I suspect you are not commiting changes to the db.

I hate to say it but I guess it’s time. I have no clue what sql profiler is, where to get it, and even if I did, I probably wouldn’t understand the output. I already get lost trying to decipher the sql exposed in exceptions.

Sql Profiler buddles with the enterprise edition you should see it under tools in management studio.

It allows you to start a tracer on sql server.

Well, I have professional, not enterprise. Anyway, I think I’m going to scrap nhibernate. It uses a level of abstraction and complexity that I just simply don’t need. Thanks for replying though.

By Professional do you mean Developer Edition, if so then it also has sql profiler. If you navigate to microsoft Sql server 2005, then performance tools, you’ll find it

This is what I have…

I use the Sql Server Express that comes with it. I have yet another need to trace some sql now because in my latest test, I get a valid, connected NHibernate.ISession, but no data is returned from session.CreateCriteria<T>().List<T>()! I stepped through up to that point and everything is fine. I checked the db and there is data present. The session has the correct connection string cached, and the SqlConnection is listed as open and ready.

Fuh???

I am not familiar with nHibernate, but is there no function to output the T-SQL that is generated? You will then be able to see the T-SQL and make sure it is correct and execute it in Management studio to make sure it is returning the correct data. Then you can take it from there.

If you use NHibernate, then you need this: http://nhprof.com/

Hell, if you use any ORM on the .Net platform, Ayende prolly has a profiler for it and they are worth every penny: http://hibernatingrhinos.com/products/UberProf

Oh, and for your problem, you need to run the query in a some kind of transaction. Can you post the code for your NHibernate repository. We use Castle’s AutomaticTransaction with the NHibernateIntegration facility, works very well, and removes sooo much bolier plate code :slight_smile:

If your looking for drag n’ drop, then NHibernate isn’t for you I’m afraid, its not really designed for that

I second dhtml, nhprof is realy a time saver for working with nhibernate.

As an alternative, although nhprof does a lot more, if you have access to SQL Server Enterprise (Developer Edition) you can use the SQL Server Profiler, with it you can start a trace and see what commands are hitting the database.
SQL Server Express doesn’t have the “Performance Tools” pack.

Sure thing. I’ll even wrap up the whole solution + current db if you want.

namespace Venue.Infrastructure.Domain.Persistence
{
    public interface IRepository<T> : IRepository<T, int> where T : Entity { }
}
using System.Collections.Generic;
namespace Venue.Infrastructure.Domain.Persistence
{
    public interface IRepository<T, I> where T : Entity<I>
    {
        IList<T> Select();
        T SelectById(I id);
        void Insert(T entity);
        void Update(T entity);
        void Delete(T entity);
    }
}
namespace Venue.Infrastructure.Persistence
{
    using Venue.Infrastructure.Domain;
    public class Repository<T> : Repository<T, int> where T : Entity { }
}
using System.Collections.Generic;
using NHibernate;
namespace Venue.Infrastructure.Persistence
{
    using Venue.Infrastructure.Domain;
    using Venue.Infrastructure.Domain.Persistence;
    using Venue.Infrastructure.Persistence.Configuration;
    public class Repository<T, I> : IRepository<T, I> where T : Entity<I>
    {
        protected ISession session = SessionManager.Factory.OpenSession();
        public IList<T> Select()
        {
            return session.CreateCriteria(typeof(T)).List<T>();
        
        }
        public T SelectById(I id)
        {
        
            return session.Get<T>(id);
        
        }
        public void Insert(T entity)
        {
        
            using (session.BeginTransaction())
            {
            
                session.Save(entity);
                session.Transaction.Commit();
            
            }
        
        }
        public void Update(T entity)
        {
        
            using (session.BeginTransaction())
            {
            
                session.Update(entity);
                session.Transaction.Commit();
            
            }
        
        }
        public void Delete(T entity)
        {
        
            using (session.BeginTransaction())
            {
            
                session.Delete(entity);
                session.Transaction.Commit();
            
            }
        
        }
    }
}

On this line:

return session.CreateCriteriaCOLOR=#000000[/COLOR].List<T>COLOR=#000000[/COLOR];

on debug inspection, session is connected, open, and ready, using the correct connection string. Why it doesn’t return any records is beyond me.

Ahaha! I found the culprit. It was in Global.asax:

        public static void InitializePersistence()
        {
            SessionManager.Configuration 
                .Database
                (
                MsSqlConfiguration.MsSql2005.ConnectionString(c => c.FromConnectionStringWithKey("VenueServices"))
                )
                .Mappings
                (
                m => m.FluentMappings.AddFromAssemblyOf<CategoryMap>().Conventions.AddFromAssemblyOf<HasManyConvention>()
                );
                
        }

Where “CategoryMap” is now, I had “Category”.

lol…

Glad you got it sorted. Because I’m sure I’ve got OCD, I cleaned up your repository. I really don’t like duplicate code :slight_smile:


public class Repository<T, I> : IRepository<T, I> where T : Entity<I>
    {
        protected ISession Session
        {
            get { return SessionManager.Factory.OpenSession();}
        }

        // Returning a List<T> isn't really correct.  It gives the impression that you can add to the list, which you can't really do
        public IEnumerable<T> Select()
        {
            return Session.CreateCriteria(typeof(T)).Future<T>();

        }
        public T SelectById(I id)
        {
            return Session.Get<T>(id);
        }

        public void Insert(T entity)
        {
            WithTransaction(() => Session.Save(entity));
        }

        public void Update(T entity)
        {
            WithTransaction(() => Session.Update(entity));
        }

        public void Delete(T entity)
        {
            WithTransaction(() => Session.Delete(entity));
        }

        private void WithTransaction(Action action)
        {
            using (var tx = Session.BeginTransaction())
            {
                action();
                tx.Commit();
            }
        }
    }

:slight_smile:

Oh sweet. I’lll update the file shortly. And at the same time, you gave me a very simple example of how to use “() => something”. I never quite understood that. Thanks!

One question though: // Returning a List<T> isn’t really correct. It gives the impression that you can add to the list, which you can’t really do

This won’t affect how NHibernate fills a property in an entity like the below will it?

// the nhibernate cache
private IList<Forums> forums = new List<Forum>()

// the public accessor to use classmap on
public IEnumerable<Forum> Forums { get { return forums; } }

And while I’m asking, should I be using ISet (either the new System.Collections.Generic one, or the IEsi one)?

never realy used ISet (Iesis)… don’t know if the bcl ISet is supported.

from the docs

"
The mapping of an IList or array requires a seperate table column holding the array or list index (the i in foo[i]). If your relational model doesn’t have an index column, e.g. if you’re working with legacy data, use an unordered ISet instead. This seems to put people off who assume that IList should just be a more convenient way of accessing an unordered collection. NHibernate collections strictly obey the actual semantics attached to the ISet, IList and IDictionary interfaces. IList elements don’t just spontaneously rearrange themselves!
On the other hand, people who planned to use the IList to emulate bag semantics have a legitimate grievance here. A bag is an unordered, unindexed collection which may contain the same element multiple times. The .NET collections framework lacks an IBag interface, hence you have to emulate it with an IList. NHibernate lets you map properties of type IList or ICollection with the <bag> element. Note that bag semantics are not really part of the ICollection contract and they actually conflict with the semantics of the IList contract (however, you can sort the bag arbitrarily, discussed later in this chapter). "

http://nhforge.org/doc/nh/en/index.html#collections-persistent