nhibernate mapping: A collection with cascade=“all

2019-01-24 02:01发布

问题:

I am having some probs with my fluent mappings. I have an entity with a child collection of entities i.e Event and EventItems for example.

If I set my cascade mapping of the collection to AllDeleteOrphan I get the following error when saving a new entity to the DB: NHibernate.HibernateException : A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: Core.Event.EventItems

If I set the cascade to All it works fine? Below are my classes and mapping files:

 public class EventMap : ClassMap<Event>
{
    public EventMap()
    {
        Id(x => x.Id, "Id")
            .UnsavedValue("00000000-0000-0000-0000-000000000000")
            .GeneratedBy.GuidComb();

        Map(x => x.Name);
        HasMany(x => x.EventItems)
            .Inverse()
            .KeyColumn("EventId")
            .AsBag()
            .Cascade.AllDeleteOrphan();
    }
}

  public class EventItemMap : SubclassMap<EventItem>
{
    public EventItemMap()
    {
         Id(x => x.Id, "Id")
            .UnsavedValue("00000000-0000-0000-0000-000000000000")
            .GeneratedBy.GuidComb();
        References(x => x.Event, "EventId");
    }
}



public class Event : EntityBase
{
    private IList<EventItem> _EventItems;

    protected Event()
    {
        InitMembers();
    }

    public Event(string name)
        : this()
    {
        Name = name;
    }

    private void InitMembers()
    {
        _EventItems = new List<EventItem>();
    }

    public virtual EventItem CreateEventItem(string name)
    {
        EventItem eventItem = new EventItem(this, name);
        _EventItems.Add(eventItem);
        return eventItem;
    }

    public virtual string Name { get; private set; }
    public virtual IList<EventItem> EventItems
    {
        get
        {
            return _EventItems.ToList<EventItem>().AsReadOnly();
        }
        protected set
        {
            _EventItems = value;
        }
    }
}

    public class EventItem : EntityBase
{
    protected EventItem()
    {
    }

    public EventItem(Event @event, string name):base(name)
    {
        Event = @event;
    }

    public virtual Event Event { get; private set; }
}

Pretty stumped here. Any tips greatly appreciated.

Chev

回答1:

You need to map _EventItems using an access strategy so that NHibernate access the private member instead of the property. You're getting this error because the collection reference is changed when the list is copied to a new List in _EventItems.ToList<EventItem>(). Try this:

public class EventMap : ClassMap<Event>
{
    public EventMap()
    {
        Id(x => x.Id, "Id")
            .UnsavedValue("00000000-0000-0000-0000-000000000000")
            .GeneratedBy.GuidComb();

        Map(x => x.Name);
        HasMany(x => x.EventItems)
            .Access.PascalCaseField(Prefix.Underscore)
            .Inverse()
            .KeyColumn("EventId")
            .AsBag()
            .Cascade.AllDeleteOrphan();
        }
    }
}


回答2:

I don't think the accepted answer is an elegant approach. The possible problem here is that Chev is reading Events from the database and then assigning a new EventItem list to the EventItems property. NHibernate throws this exception when you just ignore the previous children list and assign a new children list.

What you need to do here is,

If you want to discard the old EventItems, do this instead:

events.EventItems.Clear();
events.EventItems.Add(new EventItem { blah blah });


回答3:

Check this SO post: NHibernate: Delete a child record from the parent collection

The comments to the accepted answer has similar issue.

You may want to try removing AsReadOnly for your EventItems to check if that's the cause.