views:

254

answers:

3

Hi guys, I'm having a bit of an issue with Nhibernate / Fluent NHibernate

I have a class that has a collection and a backing field, and methods for manipulating the collection like so:

Edit: I've added the virtual modifier to Children since I forgot to stick it in the example code below (it was 2 am)

public class MyClass
{
    private IList<SomeChildObject> children;

    public virtual IList<SomeChildObject> Children { get { return new ReadOnlyCollection<SomeChildObject>(children); } }

    public void AddToChildren(SomeChildObject obj)
    {
        children.Add(obj);
    }
}

And I have my Fluent NHibernate mapping like this:

public class MyClassMapping : ClassMap<MyClass>
{
    public MyClassMapping()
    {
        HasMany(x => x.Children)
            .Inverse()
            .LazyLoad()
            .Cascade.AllDeleteOrphan()
            .KeyColumnNames.Add("MyClassID")
            .Access.AsReadOnlyPropertyThroughCamelCaseField();
    }
}

Now all is good when I pull back an instance of MyClass from the database.

MyClass myClass = repo.GetById(12);

myClass.AddToChildren(new SomeChildObject());

This works fine.

And then I make some changes and persist the changes to the database.

Once the changes have been saved, I then try and add another child object

myClass.AddToChildren(new SomeChildObject("Another One!!!"));

And it falls over with "InvalidOperationException: The Collection is ReadOnly"

Seems the NHibernate is doing something somewhere in it's proxy. Does anyone know how to resolve this issue?

Thanks in advance.

A: 

Given that children is a private field, it's not possible for the proxy to be modifying it, as the proxy can only front virtual fields and properties, unless there's some way to set children that isn't in your code. It certainly looks very bizarre, but we would need to see the rest of the class that applies to this.

Deeksy
Nope no other way for setting `children` except in the constructor.
Sekhat
(Which initializes it with `new List<SomeChildObject>()`
Sekhat
+1  A: 

What happens if you disable lazy loading on the entity level ? That is, make sure that NHibernate doesn't use dynamic proxies for this class ? (This has no effect on the ability of lazy loading a collection; lazy loading the collection will still work).

In my applications, I use the same approach as the one that you've demonstrated here (private collection field, property that wraps around the collection and returns a readonly list), and I do not have those issues that you're having. But, the difference is that I declare in my mapping ( I do not use fluent NHibernate, but plain old xml files :) ), that NHibernate should not use dynamic proxies for my class:

 <class name="SomeClass" table="SomeTable" lazy="false">
      <!-- rest of mapping goes here -->
   </class>
Frederik Gheysels
I'll have a look to see if Fluent NHibernate has an equivalent. (Would be suprised if not) Thanks for the suggestion.
Sekhat
It is indeed possible.`SetAttribute("lazy", "false")` did the trick :)
Sekhat
A: 

Your mapping tells nhibernate to use the public Children property, so it won't use the private field "children".

I don't think you can specify private fields in the fluent nhibernate mappings, so if you would want that, you should use an alternative mapping strategy, like xml mapping files.

You can do the following to see if this is indeed the problem:

  • make the "children" field public (for now, just to test it)
  • change the mapping to use the "private" lowercase children field
  • now see if the problem still persists
Jan Willem B