Unit testing an inverse one-to-many

83 views
Skip to first unread message

Peter

unread,
Dec 9, 2009, 6:37:54 AM12/9/09
to Fluent NHibernate
First the caveats:

1) This is a follow-on from
http://groups.google.com/group/fluent-nhibernate/browse_thread/thread/cebc70ff873e4fd2/ce6cc622bc02d9ce
(didn't want to hijack the post)
2) I'm new to nhibernate so please forgive me saying stupid things

I have exactly the same problem as described by Cristian at the top of
this post. However, the CheckList extension method still fails when
you use it to test an inverse on-to-many with the child FK column set
to non-nullable. A PropertyValueException is thrown: "not-null
property references a null or transient value XXX"

For example:

public class ArtistMap : ClassMap<Artist>
{
public ArtistMap()
{
[...]
References(a => a.Genre)
.Column("GenreID")
.Not.Nullable();
}
}
}

public class GenreMap : ClassMap<Genre>
{
public GenreMap()
{
[...]
HasMany(g => g.Artists)
.KeyColumn("GenreID")
.Cascade.All()
.Inverse();
}
}
}

[TestClass]
public class GenreTests : DatabaseTest
{
[TestMethod]
public void ShouldMapCorrectly()
{
List<Artist> artists = new List<Artist>() {
new Artist { Name = "Artist1" },
new Artist { Name = "Artist2" }
};

new PersistenceSpecification<Genre>(Session, new Comparer())
.CheckProperty(g => g.Id, 1)
.CheckProperty(g => g.Name, "Genre")
.CheckList(g => g.Artists, artists, (g, a) => g.AddArtist
(a))
.VerifyTheMappings();
}
}

Here's a loose call-stack of what happens in the code

1: CheckList
2: -> PersistenceSpecification.RegisterCheckedProperty
3: -> ReferenceList.HasRegistered
4: -> PersistenceSpecification.TransactionalSave
5: VerifyTheMappings
6: -> InstantiateUsingParameterlessConstructor
7: -> Genre.AddArtist

So, before fluent gets anywhere close to invoking my setter delegate
(7) it first persists the new artists object (4). As the artist type
is configured to have a genre FK that is not nullable, the test fails
at (4) and throws the 'transient object' exception.

Does this mean that CheckList is only good for unidirectional
associations or associations where the FK column is nullable? If there
is a nullable FK column, then the test should be re-written the long
way to manually persist the objects, reload them and verify the values
are correct?

Alexander Groß

unread,
Dec 16, 2009, 7:56:30 AM12/16/09
to Fluent NHibernate
Hi Peter,

I must admit that I never wrote a PersistenceSpecification involving a
relation like to one you describe.

I guess the problem can be solved by just not calling
TransactionalSave on your artists but rather let NH save the artists
along with the Session. Right off the top of my head, here's what you
can to let the ReferenceList skip the TransactionalSave:

1. Derive a class from ReferenceList
2. Override HasRegistered in that class and let it do nothing
3. Add an extension method
PersistenceSpecification<T>.CheckListWithoutSavingTheItems with the
same signature as CheckList
4. CheckListWithoutSavingTheItems would have to instantiate the class
created in step 1 and register it on the PersistenceSpecification

This will cause your overridden "no-op" HasRegistered method to be
called, allowing the setter delegate to run. What also might be needed
is a custom equality comparer for Artist. ReferenceList knows about
artists with a unassigned PK, whereas the artists that are read from
the DB got a PK assigned.

All of the steps above can be implemented in your code so you don't
need to touch FNH. If it works, I think the FNH team will be happy to
integrate your new check.

Hope this helps,

Alex

On 9 Dez., 12:37, Peter <peter.ad...@triggerfishsoftware.co.uk> wrote:
> First the caveats:
>
> 1) This is a follow-on fromhttp://groups.google.com/group/fluent-nhibernate/browse_thread/thread...

Paul Batum

unread,
Dec 16, 2009, 4:24:31 PM12/16/09
to fluent-n...@googlegroups.com
Thanks Alex. I do think we should get something into the FNH code base
for this as the approach of relying on cascades for saving the
children rather than saving them individually is a pretty common one.

2009/12/16 Alexander Groß <agr...@therightstuff.de>:
> --
>
> You received this message because you are subscribed to the Google Groups "Fluent NHibernate" group.
> To post to this group, send email to fluent-n...@googlegroups.com.
> To unsubscribe from this group, send email to fluent-nhibern...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/fluent-nhibernate?hl=en.
>
>
>

Alexander Groß

unread,
Dec 17, 2009, 7:29:07 AM12/17/09
to fluent-n...@googlegroups.com
While looking at the code, I saw that we actually have a check that does not
call TransactionalSave on the list items. It's List<T> (from which
ReferenceList<T> derives, adding the TransactionalSave) which is registered
by CheckComponentList.

I'll start with re-implementing Peter's use case in a test fixture and see
how it works.

Alex
--
Alexander Groß
http://therightstuff.de/

| nhibernate+...@googlegroups.com.


| > For more options, visit this group at
| http://groups.google.com/group/fluent-nhibernate?hl=en.
| >
| >
| >
|

| --
|
| You received this message because you are subscribed to the Google Groups
| "Fluent NHibernate" group.
| To post to this group, send email to fluent-n...@googlegroups.com.
| To unsubscribe from this group, send email to fluent-

| nhibernate+...@googlegroups.com.

Alexander Groß

unread,
Dec 17, 2009, 8:11:24 AM12/17/09
to fluent-n...@googlegroups.com
Peter, CheckComponentList did the trick, also without a custom comparer for
the Artist class:
http://xrl.in/4147

Paul, I think we should rename the PersistenceSpecification's extension
methods to match their semantics (or add new ones).

Alex
--
Alexander Groß
http://therightstuff.de/


| -----Original Message-----
| From: fluent-n...@googlegroups.com [mailto:fluent-
| nhibe...@googlegroups.com] On Behalf Of Paul Batum
| Sent: Wednesday, December 16, 2009 10:25 PM
| To: fluent-n...@googlegroups.com
| Subject: Re: [fluent-nhib] Re: Unit testing an inverse one-to-many
|

| nhibernate+...@googlegroups.com.


| > For more options, visit this group at
| http://groups.google.com/group/fluent-nhibernate?hl=en.
| >
| >
| >
|

| --
|
| You received this message because you are subscribed to the Google Groups
| "Fluent NHibernate" group.
| To post to this group, send email to fluent-n...@googlegroups.com.
| To unsubscribe from this group, send email to fluent-

| nhibernate+...@googlegroups.com.

Paul Batum

unread,
Dec 17, 2009, 4:20:42 PM12/17/09
to fluent-n...@googlegroups.com
Yeah I agree.

2009/12/18 Alexander Groß <agr...@therightstuff.de>

epitka

unread,
Dec 30, 2009, 2:26:30 PM12/30/09
to Fluent NHibernate
Where are these extension methods?

> > | nhibernate+...@googlegroups.com<nhibernate%2Bunsubscribe@googlegrou ps.com>


> > .
> > | > For more options, visit this group at
> > |http://groups.google.com/group/fluent-nhibernate?hl=en.
> > | >
> > | >
> > | >
> > |
> > | --
> > |
> > | You received this message because you are subscribed to the Google Groups
> > | "Fluent NHibernate" group.
> > | To post to this group, send email to fluent-n...@googlegroups.com.
> > | To unsubscribe from this group, send email to fluent-

> > | nhibernate+...@googlegroups.com<nhibernate%2Bunsubscribe@googlegrou ps.com>

epitka

unread,
Dec 30, 2009, 8:33:54 PM12/30/09
to Fluent NHibernate
Nevermind, they are in the trunk. But CheckList is not working.

This code never calls action delegate specified in CheckList. I debug
it and it never gets called.

var project = Session.CreateCriteria(typeof (MetaProject))
.List<MetaProject>().First();

MetaPackage metaPackage1 =project.CreateMetaPackage
("Name1");
metaPackage1.Description = "Description";

MetaPackage metaPackage2 = project.CreateMetaPackage
("Name2");
metaPackage2.Description = "Description";

var packages = new List<MetaPackage>() {metaPackage1,
metaPackage2};


var ps = new PersistenceSpecification<MetaProject>
(Session);
ps.CheckProperty(x => x.Name, "Name")
.CheckProperty(x => x.Description, "Description")
.CheckList(x => x.MetaPackages, packages, (x,p)=>
x.MetaPackages_Add(p))
.VerifyTheMappings();

Alexander Groß

unread,
Jan 1, 2010, 7:34:24 AM1/1/10
to fluent-n...@googlegroups.com
epitka,

Can you please provide a failing test for your scenario, like this one:
http://github.com/agross/fluent-nhibernate/blob/master/src/FluentNHibernate.
Testing/DomainModel/InverseOneToManyTester.cs

Thanks,

| > > > | nhibernate+@googlegrou ps.com>


| > > > .
| > > > | > For more options, visit this group at
| > > > |http://groups.google.com/group/fluent-nhibernate?hl=en.
| > > > | >
| > > > | >
| > > > | >
| > > > |
| > > > | --
| > > > |
| > > > | You received this message because you are subscribed to the
| > > > | Google Groups "Fluent NHibernate" group.
| > > > | To post to this group, send email to fluent-

| nhibe...@googlegroups.com.


| > > > | To unsubscribe from this group, send email to fluent-
| > > > |
| nhibernate+...@googlegroups.com<nhibernate%2Bunsubscribe

| > > > | nhibernate+@googlegrou ps.com>


| > > > .
| > > > | For more options, visit this group at
| > > >http://groups.google.com/group/fluent-
| > > > | nhibernate?hl=en.
| > > > |
| > > > |
|

| --
|
| You received this message because you are subscribed to the Google Groups
| "Fluent NHibernate" group.
| To post to this group, send email to fluent-n...@googlegroups.com.
| To unsubscribe from this group, send email to fluent-

| nhibernate+...@googlegroups.com.

Peter

unread,
Feb 17, 2010, 5:24:01 AM2/17/10
to Fluent NHibernate
Alex,

Sorry I haven't replied sooner - I assumed I would get email
notifications about replies to this post and kind of forgot about it.

Many thanks for pointing out CheckComponentList, it's nice to have a
simple fix.

P

On Jan 1, 12:34 pm, Alexander Groß <agr...@therightstuff.de> wrote:
> epitka,
>

> Can you please provide a failing test for your scenario, like this one:http://github.com/agross/fluent-nhibernate/blob/master/src/FluentNHib....
> Testing/DomainModel/InverseOneToManyTester.cs
>
> Thanks,
> Alex
> --
> Alexander Großhttp://therightstuff.de/

>  smime.p7s
> 9KViewDownload

Reply all
Reply to author
Forward
0 new messages