Search code examples
c#mysqlnhibernatenhibernate-mapping

One to Many mapping not Cascading deletes


I have a simple model where a Player may choose a unique Selection of integers which are saved in a Selection table

Which looks like this

public class Player
{
    private readonly ICollection<Selection> selection;

    public Player()
    {
        this.selection = new List<Selection>();
    }

    public virtual long Id { get; set; }    
    public virtual string Name { get; set; }
    public virtual string EmailAddress { get; set; }

    public virtual IEnumerable<Selection> Selection
    {
        get
        {
            return this.selection;
        }
    }

    public virtual void UpdateSelection(IEnumerable<int> balls)
    {
        this.selection.Clear();
        this.selection.AddRange(balls.Select(ball => new Selection { Player = this, Number = ball }));
    }
}

public class Selection
{
    public virtual Player Player { get; set; }
    public virtual int Number { get; set; }
}

This is what I'm using to map the selection to the player

this.Bag(
    x => x.Selection,
    m =>
        {
            m.Key(k => k.Column("PlayerId"));
            m.Access(Accessor.Field);
            m.Cascade(Cascade.All);
            m.Inverse(true);
        },
    k => k.OneToMany());

And the selection map has a composed id

this.ComposedId(
    x =>
        {
            x.Property(y => y.Number);
            x.ManyToOne(y => y.Player, m => m.ForeignKey("PlayerId"));
        });

As I change this list using the UpdateSelection method of Player then the Selection table should insert and delete rows where necessary.

However, if I were to remove a number from the Selection when the Session.Update method is called I get the following error

Duplicate entry '1-1' for key 'PRIMARY'Could not execute command: INSERT INTO Selection (PlayerId, Number) VALUES (?p0, ?p1)

Which is self explanatory, but fixing it is not. Why is it trying to re-add the numbers, shouldn't it just delete the one I removed?

Update

I change the mapping from a Bag to a Set and now I don't get the duplicate key error. However it does not delete the number I removed from the list.


Solution

  • So in your mapping of the Bag (now Set) you define

            m.Cascade(Cascade.All);
            m.Inverse(true);
    

    Defining both, Cascade and Inverse(true) would work against each other... Inverse(true) means that the other side should take care of updating changes, wich would negate the Cascade definition...

    You should try to set Inverse(false) which would make the Bag responsible for the entity.