Examples.FirstProject - No Inserts to Employee table happening

972 views
Skip to first unread message

fmorriso

unread,
Feb 12, 2009, 4:20:59 PM2/12/09
to Fluent NHibernate
I'm running the Examples.FirstProject using Microsoft SQL Server 2008
Developer Edition and Visual Studio 2008 SP1, .Net Framework 3.5 SP1
and it does not generate any INSERT's for the Employee table.

The narrative for the example indicates that saving a Store object
should auto-generate any necessary Employee INSERT's, but the output
on the console shows only INSERT's for Store, Product and
StoreProduct. A SELECT * FROM dbo.[Employee] returns zero rows.

There aren't very many changes needed to switch the example to use SQL
Server 2008, but perhaps one or more of those changes I made could
have disabled the automatic generation of Employee INSERT
statements? I hate to post tons of code, so if somebody could email
me to show me how to upload the code, I'd be glad to share it - and
maybe learn something in the process.

Here's just a small example of a change I made to allow the example to
use SQL Server 2008. Hopefully, I didn't mess it up too bad:

/// <summary>
/// Sets up the required NHibernate session factory
/// </summary>
/// <returns>ISessionFactory instance</returns>
private static ISessionFactory CreateSessionFactory()
{
string connString = GetDatabaseConnectionString();
Console.WriteLine(connString);

// Use Fluent NHibernate instead of an NHibernate XML
config file
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005
.ConnectionString(c => c.Is(connString))
.ShowSql()
.DefaultSchema("dbo")
)
.Mappings(m => m
.FluentMappings.AddFromAssemblyOf<Program>()
)
//WARNING: will DROP/CREATE tables .ExposeConfiguration
(BuildSchema)
.BuildSessionFactory();
}

I built the database myself (so I'm a control freak, sue me) rather
than end up with weird PK and FK constraint names.

The DDL for the Employee table looks like this:

CREATE TABLE [dbo].[Employee](
[Id] [int] IDENTITY(1,1) NOT NULL,
[LastName] [nvarchar](100) NOT NULL,
[FirstName] [nvarchar](100) NOT NULL,
[Store_id] [int] NULL,
CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[Employee] WITH NOCHECK
ADD CONSTRAINT [FK_Employee_Store] FOREIGN KEY([Store_id])
REFERENCES [dbo].[Store] ([Id])
GO

ALTER TABLE [dbo].[Employee] CHECK CONSTRAINT [FK_Employee_Store]
GO

The DDL for Store looks like this:

CREATE TABLE [dbo].[Store](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
CONSTRAINT [PK_Store] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

James Gregory

unread,
Feb 12, 2009, 5:56:33 PM2/12/09
to fluent-n...@googlegroups.com
Somebody else just raised this exact issue today, I'll investigate asap. Thanks.

fmorriso

unread,
Feb 12, 2009, 10:54:37 PM2/12/09
to Fluent NHibernate
FYI: If I collect the Employee object instances into a List<Employee>
and iterate through them via foreach loop and call SaveOrUpdate
method, the INSERT's into dbo.[Employee] occur. Later on, when the
example code saves the Store objects, it also generates corresponding
UPDATE EMPLOYEE ... SET Store_Id ... WHERE Id = ...., so hopefully,
whatever part of Fluent NHibernate doesn't realize that the unsaved
Stored instances contain a List<Employee> of unsaved Employee
instances can be corrected in short order and I can remove my
temporary work-around.
> > GO- Hide quoted text -
>
> - Show quoted text -

fmorriso

unread,
Feb 15, 2009, 3:30:23 PM2/15/09
to Fluent NHibernate
For what it's worth, here's the code for my temporary work-around.
Put it after this line in Program.cs:

var joan = new Employee { FirstName = "Joan", LastName = "Pope" };

// added by Fred Morrison because Store objects
don't seem to save the Employee's
// that work in the store.
var employees = new List<Employee>() { daisy,
jack, sue, bill, joan };
foreach (var employee in employees)
{
session.SaveOrUpdate(employee);
Console.WriteLine(employee.Id);
}

On Feb 12, 5:56 pm, James Gregory <jagregory....@gmail.com> wrote:
> Somebody else just raised this exact issue today, I'll investigate asap.
> Thanks.
>

x97mdr

unread,
Feb 18, 2009, 6:48:35 PM2/18/09
to Fluent NHibernate
*bump*

Just wondering if this issue was ever resolved?

fmorriso

unread,
Feb 20, 2009, 12:32:51 PM2/20/09
to Fluent NHibernate
No, the issue is still unresolved. I just pulled down the latest
Fluent NHibernate code and tried the example again and it did not
INSERT any records into table dbo.Employee when saving a new Store
object into table dbo.Store. The workaround is still needed (save any
unsaved Employee objects BEFORE attempting to save any new Store
objects that reference those unsaved Employee objects as memebers of
that store's staff).

fmorriso

unread,
Mar 3, 2009, 4:24:53 PM3/3/09
to Fluent NHibernate
FYI: still not fixed using the latest Fluent NHibernate code (last
modified Feb 26, 2009).

On Feb 18, 6:48 pm, x97mdr <jeffreycame...@gmail.com> wrote:

Eric Liprandi

unread,
Mar 3, 2009, 5:39:41 PM3/3/09
to Fluent NHibernate
FYI,

I get the same (mis)behavior on SQL 2005. So I don't believe it's an
issue with the DB back-end.
I did notice that adding .Cascade.All() to the StoreMap class like
that:
HasMany(x => x.Staff)
.Cascade.All()
.Inverse();

Though I am new to the whole Fluent NHibernate and Hibernate in
general, I have noticed that the Cascade.All() is pretty much
mendatory if I want to have "child" object be saved... Not sure why.

Regards,

Eric.
> > - Show quoted text -- Hide quoted text -

James Gregory

unread,
Mar 3, 2009, 5:53:42 PM3/3/09
to fluent-n...@googlegroups.com
Eric: It's mandatory if you want the child to be saved when saving the parent; hence the cascading. It's not mandatory if you save the children yourself.

James Gregory

unread,
Mar 3, 2009, 5:54:43 PM3/3/09
to fluent-n...@googlegroups.com
Take the lack of a response as an acknowledgement of the bug. I need not reminding about it's existence, just the time to fix it.

x97mdr

unread,
Mar 4, 2009, 7:57:10 AM3/4/09
to Fluent NHibernate
Ha! If it can be fixed that would be great, any help is much
appreciated.

... and thanks for taking the time to do this project in the first
place. Making open source software is a labor of love! It needs some
recognition once in a while so here's the recognition :)

On Mar 3, 5:54 pm, James Gregory <jagregory....@gmail.com> wrote:
> Take the lack of a response as an acknowledgement of the bug. I need not
> reminding about it's existence, just the time to fix it.
>

kellyb

unread,
Mar 14, 2009, 9:48:05 PM3/14/09
to Fluent NHibernate
Bless you all for making this library - I love it.

I'm experiencing this same problem. The many-to-many seems to be
working fine, but not the one-to-many

fmorriso

unread,
Mar 17, 2009, 2:13:39 PM3/17/09
to Fluent NHibernate
I've been able to manually "marry up" Fluent NHibernate with
NHibernate 2.1 (a long involved process that already exceeds 5 pages
of steps). Even after doing so this issue remained until I changed
storemap.cs to this:

namespace Examples.FirstProject.Mappings
{
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
Id(x => x.Id);
Map(x => x.Name);

HasManyToMany(x => x.Products)
.Cascade.All()
.WithTableName("StoreProduct");

HasMany(x => x.Staff)
.Inverse()
.Cascade.All()
;
}
}
}

To prove to myself that it was working with the above change (and also
to prove that it fails without that change), I changed method main to
separate out the session that writes the objects from the one that
retrieves them. Some partial code snippets follow:

using (var session = sessionFactory.OpenSession())
{
// populate the database
using (var transaction = session.BeginTransaction())
{
// create a couple of Stores each with some
Products and Employees
var barginBasin = new Store { Name = "Bargin
Basin" };
var superMart = new Store { Name = "SuperMart" };

<snip>

// save both stores, this saves everything else
via cascading
session.SaveOrUpdate(barginBasin);
session.SaveOrUpdate(superMart);

transaction.Commit();
}
session.Close();
}

// Do the Employees get saved when we save the Store
instance that they work in ?
using (var session = sessionFactory.OpenSession())
{
// retreive all stores and display them
using (session.BeginTransaction())
{
var stores = session.CreateCriteria(typeof(Store))
.List<Store>();

foreach (var store in stores)
{
WriteStorePretty(store);
}
}

Console.ReadKey();
}
}

My version of CreateSessionFactory looks like this (note the use of
ProxyFactoryFactory) and required adding an explicit Reference to the
NHibernate.ByteCode.LinFu assembly in order to make it work correctly:

/// <summary>
/// Sets up the required NHibernate session factory
/// </summary>
/// <returns>ISessionFactory instance</returns>
private static ISessionFactory CreateSessionFactory()
{
string connString = GetDatabaseConnectionString();
Console.WriteLine(connString);

ISessionFactory returnValue = null;

// Use Fluent NHibernate instead of an NHibernate XML
config file
returnValue = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(c => c.Is(connString))
.ShowSql()
.DefaultSchema("dbo")
.ProxyFactoryFactory
("NHibernate.ByteCode.LinFu.ProxyFactoryFactory,
NHibernate.ByteCode.LinFu")
)
.Mappings(m => m
.FluentMappings.AddFromAssemblyOf<Program>()
)
//WARNING: will DROP/CREATE
tables .ExposeConfiguration (BuildSchema)
.BuildSessionFactory()
;

return returnValue;
}

The above also required my adding the following lines to
MsSqlConfiguration.cs to take advantage of NHibernate 2.1 support of
SQL Server 2008:

public static MsSqlConfiguration MsSql2008
{
get { return new MsSqlConfiguration
().Dialect<MsSql2008Dialect>(); }
> > > > > - Show quoted text -- Hide quoted text -
Reply all
Reply to author
Forward
0 new messages