4

I have a very simple object models.

public class Contact
{
    public virtual int Id                { get; set; }
    public virtual string Name           { get; set; }
    public virtual Device Device         { get; set; }
    public virtual IList<string> Numbers { get; set; }

    public Contact()
    {
        Numbers = new System.Collections.Generic.List<string>(3);
    }
}

As you can see, the class Contact has an association with Numbers, which is a list of strings.

Here's the mapping:

        Id(x => x.Id).GeneratedBy.Assigned();
        Map(x => x.Name);
        References(x => x.Device, "DeviceId");
        Table("Contacts");
        HasMany(x => x.Numbers)
            .Table("ContactNumbers")
            .Element("Number")
            .KeyColumn("ContactId")
            .LazyLoad()
            .Cascade.All()
            .Not
            .Inverse();

Note that I can't and don't want the collection to be inverse=true, because it's just a collection of string. This means that Contact is responsible for updating Numbers entries. Now my problem is that, whenever I try to add a new number to an existing Contact, it deletes all associated numbers and recreates them individually. Isn't NHibernate smart enough to detect changes and update only changed items?

I think there should be a simple solution for my problem but don't know what.

Any help would be appreciated.

Davita
  • 8,928
  • 14
  • 67
  • 119

1 Answers1

7

This is actually documented in NHibernate's documentation.

Bags are the worst case. Since a bag permits duplicate element values and has no index column, no primary key may be defined. NHibernate has no way of distinguishing between duplicate rows. NHibernate resolves this problem by completely removing (in a single DELETE) and recreating the collection whenever it changes. This might be very inefficient.

Try using an <idbag> mapping instead, and create a surrogate primary key for that table. Unfortunately, looks like <idbag> is not yet supported in FluentNHibernate.

Also, take a look at other collection mapping options.

Miroslav Popovic
  • 12,100
  • 2
  • 35
  • 47
  • Thanks, I'll try your suggestion and let's see what happens :) – Davita Jul 10 '12 at 15:23
  • Well, that's my luck :(. Any other alternatives? :( – Davita Jul 10 '12 at 15:26
  • I guess you could use hbm or mapping-by-code, just for that entity... or try with list mapping instead: http://ayende.com/blog/4043/nhibernate-mapping-list. FluentNHibernate supports it: `HasMany...AsList()`. – Miroslav Popovic Jul 10 '12 at 15:33
  • Thanks Miraslav, I think your last suggestion is closest to my needs, however it has some caveats when removing items from collection and that's what's keeping me from using it :(. mapping with hbm file is also out of question due to the policy. So I guess there is no other way left? :( – Davita Jul 10 '12 at 15:54
  • Well, you can always add support for `idbag` to FNH. It's open source after all :) How about `` mapping then? You would need to modify property type to Iesi.Collection's `ISet` though, or try to use .NET 4.0's `ISet`: http://nhforge.org/blogs/nhibernate/archive/2011/03/15/using-lt-set-gt-in-mappings-without-iesi-collections-net-4.aspx. – Miroslav Popovic Jul 10 '12 at 16:07
  • Thanks for that answer Miroslav, I had the same issue with my collections and after adding making it inverse the problem went away, but I still couldn't work out why it was trying to delete the child collection every time - this answers the question! – Charleh Jul 10 '12 at 16:13
  • Aslo I knew your name was familiar, remember seeing you on Rocky's CSLA forums! – Charleh Jul 10 '12 at 16:15
  • Yes, I also thought about ISet, but it can contain only unique values, and in my case, duplicates is possible. Damn, It's too complicated :D – Davita Jul 10 '12 at 16:18
  • @Charleh LOL... those were the good days :) I've been working on CSLAgen looong time ago. – Miroslav Popovic Jul 10 '12 at 16:23
  • @Davita Guess YYY's suggestion for a full blown entity is not that repulsive anymore ;) – Miroslav Popovic Jul 10 '12 at 16:24
  • @MiroslavPopovic wait, having a full blown entity as a collection of bag will fix my primary issue? :) – Davita Jul 10 '12 at 16:25
  • it should... since you'll have an id / primary key in that case. – Miroslav Popovic Jul 10 '12 at 16:28
  • @MiroslavPopovic I understand muuuch better now the magic involved behind the scenes. Thank you very much for pointing me to the right direction. I'll mark your answer as answer and upvote YYY :) – Davita Jul 10 '12 at 16:43
  • @Davita not a problem, glad I could help – Miroslav Popovic Jul 10 '12 at 16:44