Perplexing Problem

305 views
Skip to first unread message

x97mdr

unread,
Feb 10, 2009, 9:24:47 PM2/10/09
to Fluent NHibernate
I am just starting to learn NHibernate now, I tried setting up a very
simple example to play around and for some reason I cannot get
cascading to work. I followed the example of the FirstExample project
and tried to apply it to my domain. I have two classes with a one-to-
many relationship between them. They are Variable and Relation
(related to metadata we store in our environment).

The problem is that when I run the unit test which should save the
relation and the related variable only the relation ever gets saved,
if at all.

I have tried what seems to me to be every variation of the mappings to
see if they would work but nothing has succeeded. The weird thing is,
the FirstExample project (for both SQLite and when I point it to SQL
Server Express) seem to work fine. There is something I am
misunderstanding in my mappings. I even tried switching between using
Save and SaveOrUpdate on the session variable. I'm using the trunk of
the fluent-nhibernate project, including the nhibernate library in its
tools directory (2.0.1)

Any help is greatly appreciated and sorry if its a bit of a newb
question but its really bugging me!

Here are the classes for reference:

public class Variable : IEntity
{
public virtual long Id
{
get;
set;
}

public virtual Relation ParentRelation
{
get;
set;
}
}

public class Relation : IEntity
{
public virtual long Id
{
get;
set;
}

public virtual IList<Variable> Variables
{
get;
set;
}

public Relation()
{
Variables = new List<Variable>();
}

public virtual void AddQuestion(Variable item)
{
item.ParentRelation = this;
Variables.Add(item);
}
}

and here are the mappings:

public class VariableMap : ClassMap<Variable>
{
public VariableMap()
{
Id(x => x.Id);
References(x => x.ParentRelation);
}
}

public class RelationMap : ClassMap<Relation>
{
public RelationMap()
{
Id(x => x.Id);
HasMany(x => x.Variables)
.Inverse()
.Cascade.All();
}
}

I have a little session provider to configure everything here:

public class MySessionProvider
{
private NHibernate.ISessionFactory _sessionFactory;
private NHibernate.Cfg.Configuration _configuration;

public MySessionProvider()
{
_sessionFactory = Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2005
.ConnectionString(x => x.Is
(@"Server=BUMBLEBEE
\SQLEXPRESS;Database=EditImputation;Trusted_Connection=True;"))
.ShowSql()
)
.Mappings(x =>
x.FluentMappings.AddFromAssemblyOf<Relation>())
.ExposeConfiguration
(StoreConfiguration)
.BuildSessionFactory();
}

private void StoreConfiguration(NHibernate.Cfg.Configuration
configuration)
{
_configuration = configuration;
}

public NHibernate.ISession CreateSession()
{
return _sessionFactory.OpenSession();
}

public void BuildSchema()
{
new NHibernate.Tool.hbm2ddl.SchemaExport
(_configuration).Create(false, true);
}
}

And I run everything in a unit test like this:

[TestMethod]
public void Can_Add_Variable()
{
var relation = new Relation();
relation.Id = 9;

var variable = new Variable();
variable.Id = 99;

relation.AddQuestion(variable);

using (var session = sessionProvider.CreateSession())
{
using (var transaction = session.BeginTransaction())
{
session.Save(relation);
}
}
}

Paul Batum

unread,
Feb 10, 2009, 9:35:21 PM2/10/09
to fluent-n...@googlegroups.com
Hi there,

I'm not sure what the problem is, but everything you are doing seems perfectly normal EXCEPT assigning the ID's. Have you tried it without assigning IDs explicitly?

Paul Batum

x97mdr

unread,
Feb 11, 2009, 6:03:04 AM2/11/09
to Fluent NHibernate
Hrm, I just tried that and no dice. :(

I was assigning the IDs because originally I wanted string-based
identifiers (I'm applying this to a legacy database) so I had to
assign the Id (or key name) to the objects.

This is sooo frustrating, It seems like such a simple problem. I'll
turn on full log4net later today and see what happens with it.

Any other suggestions in the meantime?

On Feb 10, 9:35 pm, Paul Batum <paul.ba...@gmail.com> wrote:
> Hi there,
>
> I'm not sure what the problem is, but everything you are doing seems
> perfectly normal EXCEPT assigning the ID's. Have you tried it without
> assigning IDs explicitly?
>
> Paul Batum
>

James Gregory

unread,
Feb 11, 2009, 6:11:14 AM2/11/09
to fluent-n...@googlegroups.com
You're not committing the transaction after your save. Have you tried that?

x97mdr

unread,
Feb 11, 2009, 7:02:51 AM2/11/09
to Fluent NHibernate
I have tried it at times (though honestly, I have tried so many things
now I'm not sure what I have tried together). Originally I started
out with a repository pattern object that automatically wrapped the
save in a transaction and committed it. I will give it another shot
tonight though, I don't have the project here at work.

When the IDbTransaction is in a using statement do you still have to
commit it?

On Feb 11, 6:11 am, James Gregory <jagregory....@gmail.com> wrote:
> You're not committing the transaction after your save. Have you tried that?
>

James Gregory

unread,
Feb 11, 2009, 7:08:07 AM2/11/09
to fluent-n...@googlegroups.com
Yes, you need to explicitly commit a transaction otherwise it gets rolled back in the dispose. Although sometimes it can seem like things are being saved, generally cascades don't occur until the transaction is committed.

x97mdr

unread,
Feb 11, 2009, 7:11:23 AM2/11/09
to Fluent NHibernate
In addition to my latest response, I should add that at some times I
have been able to get the Relation object to save, but the Variable
object never gets "cascade-saved" to the database.

On Feb 11, 6:11 am, James Gregory <jagregory....@gmail.com> wrote:
> You're not committing the transaction after your save. Have you tried that?
>

x97mdr

unread,
Feb 11, 2009, 7:35:07 PM2/11/09
to Fluent NHibernate
OK I changed my test fixture to this:

[TestMethod]
public void Can_Add_Variable()
{
var relation = new Relation();
var variable = new Variable();
relation.AddVariable(variable);

using (var session = sessionProvider.CreateSession())
{
using (var transaction = session.BeginTransaction())
{
session.Save(relation);
transaction.Commit();
}
}
}

And the relation is saving, but the variable is not. So no cascading
is happening. Then I modified the VariableMap class to this:

public class VariableMap : ClassMap<Variable>
{
public VariableMap()
{
Id(x => x.Id);
References(x => x.ParentRelation)
.Cascade.All();
}
}

And it works, though my Variable table has three columns Id,
ParentRelation_id and Relation_id where Relation_id remains NULL.

Any thoughts? It's weird that I had to ask the Cascade.All() to the
References column of the variable when it doesn't appear to be needed
based on the FirstExample project. Also, weird that there are three
columns on the Variable table when I would expect at most 2 columns
since ParentRelation is set to be the References in the mapping.

Would it be helpful for me to post my entire solution I wonder?

Thansk so much for your suggestions thus far.

On Feb 11, 7:08 am, James Gregory <jagregory....@gmail.com> wrote:
> Yes, you need to explicitly commit a transaction otherwise it gets rolled
> back in the dispose. Although sometimes it can seem like things are being
> saved, generally cascades don't occur until the transaction is committed.
>

James Gregory

unread,
Feb 12, 2009, 3:58:36 AM2/12/09
to fluent-n...@googlegroups.com
Your table is ending up with three columns because the HasMany in Relation is called Variables but the other side of the relation is called ParentRelation; this is causing FNH to not see them as two sides of the same relationship. Try calling TheColumnNameIs on your ParentRelation and giving it "Relation_id".

Making that change might actually fix your saving issue.

James Gregory

unread,
Feb 12, 2009, 3:59:38 AM2/12/09
to fluent-n...@googlegroups.com
Sorry, that should have been WithKeyColumn rather than TheColumnNameIs.

x97mdr

unread,
Feb 12, 2009, 9:32:13 AM2/12/09
to Fluent NHibernate
I renamed the Relation field back to ParentRelation and modified the
VariableMap back to this:

public class VariableMap : ClassMap<Variable>
{
public VariableMap()
{
Id(x => x.Id);
References(x => x.ParentRelation)
.WithForeignKey("Relation_id")
.TheColumnNameIs("Relation_id")
.Cascade.All();
}
}

The appropriate columns are now created, but the cascading no longer
works. :( Relation seems to have been created, but the Variable
information was not. Is there a bug in here somewhere?

Actually, I just tried running the FirstExample project from the trunk
again (which I was using as an example for my own project here). When
I replaced the configuration to point to SQL Server (see below for
modified CreateSessionFactory method) the References relationship does
not work there either ... I really think there is a bug here with the
References or HasMany methods, either that or its my configuration,
but my config is pretty basic. Try the FirstExample project but
examine the database after it has run (save it to SQL Server or
something) and see if the information is actually persisted in the
tables or not.

private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration
.MsSql2005
.ConnectionString(x => x.Is
(@"Server=BUMBLEBEE
\SQLEXPRESS;Database=EditImputation;Trusted_Connection=True;"))
.ShowSql())
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf<Program>())
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}


On Feb 12, 3:59 am, James Gregory <jagregory....@gmail.com> wrote:
> Sorry, that should have been WithKeyColumn rather than TheColumnNameIs.
>
> On Thu, Feb 12, 2009 at 8:58 AM, James Gregory <jagregory....@gmail.com>wrote:
>
> > Your table is ending up with three columns because the HasMany in Relation
> > is called Variables but the other side of the relation is called
> > ParentRelation; this is causing FNH to not see them as two sides of the same
> > relationship. Try calling TheColumnNameIs on your ParentRelation and giving
> > it "Relation_id".
> > Making that change might actually fix your saving issue.
>
> ...
>
> read more »

James Gregory

unread,
Feb 12, 2009, 9:33:58 AM2/12/09
to fluent-n...@googlegroups.com
The FirstProject example was originally written against SQLExpress, but I'll have a test tonight.

x97mdr

unread,
Feb 12, 2009, 5:50:10 PM2/12/09
to Fluent NHibernate
Thanks, I would like to make sure I'm not going crazy! :) For
reference, when I ran the FirstExample project every table was
populated except for Employee.

On Feb 12, 9:33 am, James Gregory <jagregory....@gmail.com> wrote:
> The FirstProject example was originally written against SQLExpress, but I'll
> have a test tonight.
>
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages