Problem with "many-to-one" relation ("References(x => x.Something)" in FluentNH)

15 views
Skip to first unread message

forki23

unread,
Jan 7, 2010, 4:28:06 AM1/7/10
to FunctionalNHibernate
Hi,

I integrated support for "many-to-one" relations ("References(x =>
x.Something)" in FluentNH) in my fork at http://bitbucket.org/forki/functionalnhibernate/
but I'm having a strange problem.

My mapping is:
...
ClassMap<Employee>
[Id <@fun x -> x.Id @>
Field <@fun x -> x.FirstName @>
Field <@fun x -> x.LastName @>]
ClassMap<Store>
[Id <@fun x -> x.Id @>
References <@fun x -> x.HeadOfStaff @> // this is a reference
to employee
HasMany <@fun x -> x.Staff @>]
...

My store is:

let store =
{ Id = 0;
HeadOfStaff = rob;
Staff =
[fred;
steffen;
// rob // adding rob will cause a strange bug?!
]; }

// save store to db
.....

// Get store from db
let store' = sessionFactory.DoInSession (fun session ->
session.Get<Store>(1))

This code works, but if I add rob to store.Staff then I'm getting this
error:

NHibernate.WrongClassException was unhandled by user code
Message=Object with id: 1 was not of the specified subclass:
Examples.FirstProject.Model.Employee (loading object was of wrong
class [Examples.FirstProject.Model.Employee])
Source=NHibernate
EntityName=Examples.FirstProject.Model.Employee

You can try this in the sample project. It seems it has something to
do with the fact that rob is loaded twice.

Regards,
Steffen

Robert Pickering

unread,
Jan 8, 2010, 1:45:06 AM1/8/10
to functional...@googlegroups.com
I've observered that NHibernate behaves differently if you set the id to zero or non-zero number. With a zero it generates an insert and automatically assigns an id, with non-zero it creates an update. I also know it does some sort of internal tracking of entites being inserted, but this will be different for our record types (as apposed to C# objects with virtual properties) as NHibernate cannot generate proxies for records. So I guess a combination of these factors is causing problems when you try and insert the same entity twice. I'll take a look at it over the weekend, there's maybe some internal NHibernate settings we need to change to get this to work as expected.

Cheers,
Rob

2010/1/7 forki23 <steffen....@msu-solutions.de>

Robert Pickering

unread,
Jan 8, 2010, 2:01:27 AM1/8/10
to functional...@googlegroups.com
Just out of interest what happens if you save the "rob" record in one transaction then add it into the store record in two places and save this in a fresh transaction? I've a feeling this may work.

Cheers,
Rob

2010/1/8 Robert Pickering <robertfp...@gmail.com>

Steffen Forkmann

unread,
Jan 8, 2010, 3:57:40 AM1/8/10
to functional...@googlegroups.com

Hi Rob,

 

the saving of the record seems to work (at least no error occurs). I’m getting the error during the loading afterwards.

 

Regards,

   Steffen

Steffen Forkmann

unread,
Jan 8, 2010, 10:05:07 AM1/8/10
to functional...@googlegroups.com

Hi,

 

I have some troubles with lazy loading. I would like to change the sample project to a version where Store.Staff is loaded lazy.

 

http://bitbucket.org/forki/functionalnhibernate/changeset/f66a37bbdae7/

 

I changed the mapping to:

 

<class name="Store" table="[Store]">

<bag cascade="all" inverse="true" lazy="true" name="Staff" collection-type="FunctionalNHibernate.FSharpListUserCollectionType`1[[Examples.FirstProject.Model.Employee, Examples.FirstProject, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]], FunctionalNHibernate, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">

</bag>

</class>

 

But it doesn’t work and I don’t see the problem.

 

Regards,

  Steffen

Robert Pickering

unread,
Jan 9, 2010, 12:29:42 PM1/9/10
to functional...@googlegroups.com
Looking at the hibernate code it looks like the IEntityPersister method IsInstance is returning false when it should return true. I'm having a little trouble figuring which object implements this interface but once I do should be fairely simple to create an F# specific version and inject this into the configuration.

I'm setting up a debugable version of nhibernate, once I have this it should make sorting this type of problem easier. I saw from some of your comments you've been using hornget for setting up dependacies. Do you have some scripts for this you can share?

Thanks,
Rob 

2010/1/8 Steffen Forkmann <steffen....@msu-solutions.de>

Robert Pickering

unread,
Jan 9, 2010, 12:31:01 PM1/9/10
to functional...@googlegroups.com
Oh, and I noticed if you use the "Inverse" function on the reference to the employees table then none of the staff seems to save at all.

Thanks,
Rob 

2010/1/9 Robert Pickering <robertfp...@gmail.com>

Robert Pickering

unread,
Jan 9, 2010, 12:37:02 PM1/9/10
to functional...@googlegroups.com
Doesn't lazy loading rely on nhibernate being able to build proxies for the objects being mapped? It can't do this with F# records since the properties are not virtual.

While the lack of proxies does have some disadvantages, it will help make things much more predicate. I think one of the big problems with nhibernate is that it can be quite difficult to understand behavior. A couple of innocent looking property accesses can end up dragging hug object graphs into memory. 

Thanks,
Rob

2010/1/8 Steffen Forkmann <steffen....@msu-solutions.de>

Hi,

Steffen Forkmann

unread,
Jan 11, 2010, 3:46:06 AM1/11/10
to functional...@googlegroups.com
Hi,

iif "References" are working we could easily use them and replace all
HasMany-Properties with a extension method like

type Store with
member this.GetStaff session =
Query.create<Staff> session
|> Query.filter <@fun x -> x.Store = this @>

I think then it would be clear that GetStaff is "lazy".

Regards,
Steffen

Steffen Forkmann

unread,
Jan 11, 2010, 4:26:41 AM1/11/10
to functional...@googlegroups.com

>> saw from some of your comments you've been using hornget for setting up dependacies.

>> Do you have some scripts for this you can share?

 

Sorry. I just went to http://www.hornget.net/packages/orm/nhcontrib/nhibernate.linq/nhibernate.linq-2.1 and downloaded the assemblies.


Regards,

  Steffen

Ryan Riley

unread,
Jan 11, 2010, 10:56:09 AM1/11/10
to functional...@googlegroups.com
Or would a seq { ... } express the intent even more and fit better syntactically? Is there a way to abstract out the proposed extension to hide it within a more familiar F# language construct?

Ryan Riley

Steffen Forkmann

unread,
Jan 11, 2010, 11:28:50 AM1/11/10
to functional...@googlegroups.com
Hi Ryan,

with the help of the "QueryMonad" sytax we can rewrite

type Store with
 member this.GetStaff session =
   Query.create<Emplyoee> session
     |> Query.filter <@fun x -> x.Store = this @>

as

type Store with
member this.GetStaff =
query {
return!
Query.create<Employee>
>> Query.filter <@fun x -> x.Store = this @> }

Which is not really nicer. So I would prefer:

type Store with
member this.GetStaff =
Query.create<Employee>
>> Query.filter <@fun x -> x.Store = this @>


But the usage looks quite nice:

let staff =
query {
let! store = Query.get<Store> 1
let! staff = store.GetStaff
return staff |> Query.toList}
|> runQuery

Or even:

let staff' =
query {
let! store = Query.get<Store> 1
return! store.GetStaff >> Query.toList}
|> runQuery

What do you think? Maybe we can rewrite

Query.create<Employee> >> Query.filter <@fun x -> x.Store = this @>

to something nicer? Maybe something like this:

type Store with
member this.GetStaff =
Query.details<Employee> <@fun x -> x.Store = this @>

Regards,
Steffen

Steffen Forkmann

unread,
Jan 11, 2010, 11:39:36 AM1/11/10
to functional...@googlegroups.com
Hi,

Maybe "details" is not the best name but I think this looks nice:

module Query =
/// Returns the details of type 'a
/// Based on the predicate
let details<'a> predicate : 'a list query =
create<'a> >> filter predicate >> toList

...

type Store with
member this.GetStaff =
Query.details<Employee> <@fun x -> x.Store = this @>

let staff =
query {
let! store = Query.get<Store> 1
return! store.GetStaff}
|> runQuery

Regards,
Steffen

Ryan Riley

unread,
Jan 11, 2010, 11:58:13 AM1/11/10
to functional...@googlegroups.com
Yeah, I like the query { ... } syntax. I had forgotten about that. It already exists, doesn't it? I suppose it is just a an aesthetic, but it's a nice one. I like the details extension, too, but is there no way to tie that into the NHibernate mapping definition?

Ryan

Robert Pickering

unread,
Jan 11, 2010, 4:07:17 PM1/11/10
to functional...@googlegroups.com
No worries, that's fine, got it building locally with horn now.

Cheers,
Rob 

2010/1/11 Steffen Forkmann <steffen....@msu-solutions.de>

Steffen Forkmann

unread,
Jan 12, 2010, 3:01:25 AM1/12/10
to functional...@googlegroups.com

>>No worries, that's fine, got it building locally with horn now.

 

Cool,

  could please mail me the patch? I’m really interested in adding this as a feature for FAKE.

 

Best Regards,

  Steffen

Robert Pickering

unread,
Jan 13, 2010, 1:59:48 AM1/13/10
to functional...@googlegroups.com
I just used "horn.exe -install:nhibernate.linq -version:2.1", but I indent to add this to the fake script along with a second to copy the resulting output to the correct tools directories.

Cheers,
Rob

2010/1/12 Steffen Forkmann <steffen....@msu-solutions.de>

Robert Pickering

unread,
Jan 13, 2010, 8:51:40 AM1/13/10
to FunctionalNHibernate
By the way I found the problem this morning but didn't have chance to
fix it before I left for work. It's actually in the FSharpTuplizer
which always returns false when calling it's is instance member. See
line 34 here:
http://bitbucket.org/robertpi/functionalnhibernate/src/tip/src/app/FunctionalNHibernate/FSharpRecordTuplizer.fs

I'll correct this tonight and probably pull all of Steffen's changes
into my branch.

Cheers,
Rob

On Jan 13, 7:59 am, Robert Pickering <robertfpicker...@gmail.com>
wrote:


> I just used "horn.exe -install:nhibernate.linq -version:2.1", but I indent
> to add this to the fake script along with a second to copy the resulting
> output to the correct tools directories.
>
> Cheers,
> Rob
>

> 2010/1/12 Steffen Forkmann <steffen.forkm...@msu-solutions.de>


>
>
>
> >  >>No worries, that's fine, got it building locally with horn now.
>
> > Cool,
>
> >   could please mail me the patch? I’m really interested in adding this as a
> > feature for FAKE.
>
> > Best Regards,
>
> >   Steffen
>

> > *Von:* functional...@googlegroups.com [mailto:
> > functional...@googlegroups.com] *Im Auftrag **von *Robert Pickering
> > *Gesendet:* Montag, 11. Januar 2010 22:07
> > *An:* functional...@googlegroups.com
> > *Betreff:* Re: Problem with "many-to-one" relation ("References(x =>


> > x.Something)" in FluentNH)
>
> > Cheers,
>
> > Rob
>

> > 2010/1/11 Steffen Forkmann <steffen.forkm...@msu-solutions.de>


>
> > >> saw from some of your comments you've been using hornget for setting up
> > dependacies.
>
> > >> Do you have some scripts for this you can share?
>
> > Sorry. I just went to

> >http://www.hornget.net/packages/orm/nhcontrib/nhibernate.linq/nhibern...downloaded the assemblies.
>
> > Regards,
>
> >   Steffen

Robert Pickering

unread,
Jan 13, 2010, 2:13:03 PM1/13/10
to FunctionalNHibernate
Okay, problem fixed. Had to remove the |> Inverse from the "HasMany <@fun x -> x.Staff @> " map as this seems to cause the staff list to be always empty.

Thanks,
Rob

2010/1/13 Robert Pickering <robertfp...@gmail.com>

forki23

unread,
Jan 15, 2010, 3:56:25 AM1/15/10
to FunctionalNHibernate
References feature seems to work correctly.

Many thanks Rob.

Robert Pickering

unread,
Jan 16, 2010, 10:24:16 AM1/16/10
to functional...@googlegroups.com
Well thanks for find the bug in the first place. I think need to go over some the NHibernate interfaces I've implmented, I have to admit I don't fully understand what all of them do. Perphas it would be better to use failwith "TODO" for any implemenation I was unsure of, this should help find this sort of bug quicker.

Cheers,
Rob

2010/1/15 forki23 <steffen....@msu-solutions.de>

Steffen Forkmann

unread,
Jan 25, 2010, 9:37:24 AM1/25/10
to functional...@googlegroups.com
Hi,

thanks to Matthew Podwysocki's excellent blog series about the reader
monad (http://bit.ly/5XbUkV)
I was able to implement Using(), While() and For() functions for the
query monad builder.

You can see the usage (in UnitTests) at
http://bitbucket.org/robertpi/functionalnhibernate/src/3c902cb7d6ca/src/
test/Test.FunctionalNHibernate/QueryMonadTest.fs

These functions allow to compose and chain queries.

Regards,
Steffen

Robert Pickering

unread,
Jan 25, 2010, 4:57:41 PM1/25/10
to functional...@googlegroups.com
Great stuff, the project is coming along nicely thanks your help.

I have a couple of features under way my self, but nothing as exciting as this. Will hopefully commit something this weekend.

Cheers,
Rob

Steffen Forkmann

unread,
Jan 26, 2010, 3:23:01 AM1/26/10
to functional...@googlegroups.com

Hi Rob,

 

my next idea is adding some Reactive Framework features to FNH.

 

At the moment I have the following code:

 

// Using For() in query

query {

    let! postingGroups = Query.getAll<CustomerPostingGroup>

    for postingGroup in postingGroups do

        let! balance = postingGroup.GetBalance

        printfn "PostingGroup: %s -> Balance %0.2f" postingGroup.Code balance}

          |> runQuery

 

 

Here I’m getting some “Posting Groups” from the database and calculate for every posting group the balance.

There is no fast way to do the calculation and needs ca. 1s per Posting Group.  

 

This is OK but I want this operation to be non-blocking. So my idea is to convert the query into a IOberservable<T>. Maybe the code could look like this:

 

let observable =

  query {

    let! postingGroups = Query.getAll<CustomerPostingGroup>

    for postingGroup in postingGroups do

        let! balance = postingGroup.GetBalance

        yield postingGroup.Code,balance}

          |> runQueryAsObservable

 

Observable.Subscribe (fun (pg,balance) -> printfn "PostingGroup: %s -> Balance %0.2f" pg balance)

 

What do you think about this?

 

Should we add the Rx dependency to the FNH main project or should I create a new project?

 

Best regards,

  Steffen

Steffen Forkmann

unread,
Jan 26, 2010, 12:02:00 PM1/26/10
to functional...@googlegroups.com
Hi Rob,

at the moment we have 16 UnitTests in our Test project.
What do you think of changing the TestFramework from plain NUnit to my
NaturalSpec project?

http://bitbucket.org/forki/naturalspec/wiki/Home


Regards,
Steffen

Robert Pickering

unread,
Jan 27, 2010, 9:59:15 AM1/27/10
to FunctionalNHibernate
Yeah, why not. I've never tried NaturalSpec, so I'd be keen to see it
in action. I'm also interested in experimenting FsCheck, but I'm not
sure how random testing would help in many of the scenarios we're
testing. Could work well in the OptionTest.fs you created but not sure
where else.

On Jan 26, 6:02 pm, "Steffen Forkmann" <steffen.forkm...@msu-

Robert Pickering

unread,
Jan 27, 2010, 10:59:43 AM1/27/10
to FunctionalNHibernate
Maybe best to create a folk for the moment. I think it's an
interesting idea, but but I'm hoping to start using FNH for a
production task soon so I'm keen to avoid something that in beta.
Reactive Framework is still quite an early beta, right? i.e. it won't
be released with VS2010 and .NET 4.0.

Cheers,
Rob

On Jan 26, 9:23 am, "Steffen Forkmann" <steffen.forkm...@msu-

Steffen Forkmann

unread,
Jan 27, 2010, 12:11:47 PM1/27/10
to functional...@googlegroups.com

Hi,

 

I converted the tests to NaturalSpec.

 

Unfortunately the output looks a bit ugly in this case:

 

Scenario: When running query which returns the session after let bang it should return the session

  - Given <fun:op_GreaterGreaterEquals@10>

     - When running query

      => It should equal <null>

  ==> Result is: <null>

  ==> OK

  ==> Time: 0.0343s

 

 

Regards,

  Steffen

Steffen Forkmann

unread,
Jan 30, 2010, 12:45:39 PM1/30/10
to functional...@googlegroups.com
Hi Rob,

my build server shows we have a small build error in FNH at the moment:

[18:28:52]: FSC : error FS0225: Source file
'.\src\app\FunctionalNHibernate\ConnectionStrings.fs' could not be found
[.\src\app\FunctionalNHibernate\FunctionalNHibernate.fsproj]
[18:28:52]: 0 Warning(s)
[18:28:52]: 1 Error(s)

Seems the ConnectionStrings.fs is missing.

Maybe I should add you as a mail recipient of our server. At least until
we can use the teamcity.codebetter.com server.

What do you think?

Best Regards,
Steffen

Steffen Forkmann

unread,
Jan 30, 2010, 12:57:08 PM1/30/10
to functional...@googlegroups.com
Seems I can't add E-Mail notifications for guest users. We use LDAP in
TeamCity and somehow it doesn't allow additional (non-LDAP) users.

Steffen Forkmann

unread,
Jan 30, 2010, 1:13:33 PM1/30/10
to functional...@googlegroups.com
I reported this as an issue to JetBrains:

http://youtrack.jetbrains.net/issue/TW-10866

-----Ursprüngliche Nachricht-----
Von: functional...@googlegroups.com [mailto:functional...@googlegroups.com] Im Auftrag von Steffen Forkmann
Gesendet: Samstag, 30. Januar 2010 18:57
An: functional...@googlegroups.com
Betreff: AW: Build error

Robert Pickering

unread,
Jan 31, 2010, 2:30:14 AM1/31/10
to functional...@googlegroups.com
Hi Steffen,

I've added the missing file. Would be great if you could add me to the mailing list of your build server, it's all too easy to forget a file or break the build in some other way.

Cheers,
Rob
Reply all
Reply to author
Forward
0 new messages