views:

304

answers:

1

I want to control my domain's interaction with a collection, so I thought I'd make the collection protected and provide a read-only wrapper around it so that the contents are visible, but I can ensure that items are not added directly to the collection.

So I have the following code:

public class MyClass
{
    public virtual ICollection<Thread> Threads
    {
        get { return new ReadOnlyWrappedCollection<Thread>(this.ThreadsInternal); }
    }

    protected virtual ICollection<Thread> ThreadsInternal { get; private set; }
}

I tried this:

this.Map(c => c.Threads)
            .Access.None();

The result was a MappingException: Could not determine type for: System.Collections.Generic.ICollection'1[[Thread]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, for columns: NHibernate.Mapping.Column(Threads)

I tried this:

this.HasMany(c => c.Threads)
            .Access.None();

The result was an InvalidOperationException: Tried to add collection 'Threads' when already added

If I omit the mapping, I get PropertyNotFoundException: Could not find a setter for property 'Threads' in class 'MyClass'

How can I persuade NHibernate to ignore this property in the mapping? I'm using Fluent NHibernate, but please post examples in hbm too.

+1  A: 

I don't think you can map an ICollection. Regardless, I'm following a similar pattern and I've found that the best way to map it is to map a private IList.

Class:

public class Invoice
{
    private IList<InvoiceItem> _items;

    public Invoice()
    {
        _items = new List<InvoiceItem>();
    }

    public virtual IEnumerable<InvoiceItem> Items
    {
        get { return _items; }
    }    
}

Mapping:

public class InvoiceMap : ClassMap<Invoice>
{
    public InvoiceMap()
    {
        Table("Invoice");

        HasMany(x => x.Items).KeyColumn("InvoiceId")
            .Access.CamelCaseField(Prefix.Underscore)
            .Cascade.AllDeleteOrphan()
            .Inverse()
            .AsBag().LazyLoad();
    }
}

The key line in the mapping is .Access.CamelCaseField(Prefix.Underscore) which tells NHibernate to use the private field _items. Note that The collection can still be cast to IList, but you could wrap it in a read only collection if needed.

Jamie Ide
Works perfectly, thanks! Incidentally, you can map to an ICollection by specifying AsSet instead of AsBag.
RichTea