Peter Morris
Peter Morris

Reputation: 23234

Unique composite index using NHibernate

NHibernate is preventing me from having a unique index that is made of a foreign key and a column when using a uni-directional association.

//The classes
public class Method
{
    public virtual Guid ID { get; private set; }
    public virtual List<MethodParameter> Parameters { get; private set; }

    public Method()
    {
        this.Parameters = new List<MethodParameter>();
    }
}

public class MethodParameter
{
    public virtual Guid ID { get; private set; }
    public virtual string Name { get; private set; }

    protected MethodParameter() { }

    public MethodParameter(Method method, string name)
    {
        this.Name = name;
        method.Parameters.Add(this);
    }
}

//The mappings
public class MAP_Method : ClassMap<Method>
{
    public MAP_Method()
    {
        this.Table("[Method]");
        this.Id(x => x.ID).Access.BackingField().GeneratedBy.GuidComb();
        this.HasMany(x => x.Parameters)
            .Access.BackingField()
            .KeyColumn("[Method]")
            .Not.LazyLoad()
            .Cascade.AllDeleteOrphan();
    }
}

public class MAP_MethodParameter : ClassMap<MethodParameter>
{
    public MAP_MethodParameter()
    {
        this.Table("[MethodParameter]");
        this.Map(x => x.Name).Length(50).Not.Nullable();
    }
}

If I create a single Method instance with two MethodParameters (Name: x and Name: y) then there is no problem. However if I create two Method instances in the same transaction with the same MethodParameter names then I get a unique index violation.

This is because I have a unique index on [MethodParameter] ([Method] ASC, [Name] ASC), and with uni-directional associations NHibernate first inserts the child tables with NULL for the [Method] column and then goes back and updates the rows with the correct [Method] values.

Obviously this is a problem when inserting two Method instances which have identical MethodParameter names because I end up with (null, "x") (null, "x") instead of (Method1, "x") (Method2, "x")

I understand that this is the designed behaviour, but it seems that I am being forced to either have bi-directional inverse association or remove the unique index from the DB. Is there a way to get NHibernate to insert the correct [Method] ID's when inserting rather than inserting NULL and then updating?

Upvotes: 1

Views: 541

Answers (1)

hazzik
hazzik

Reputation: 13344

As your association is uni-directional you have to set following options: inverse="false" on association (<one-to-many>), not-null="true" on key (<key>). If you do not plan to change owners of parameters, then you have to set update="false" on key (<key>).

It will prevent from inserting null to FK column.

Example with FluentNHibernate:

this.HasMany(x => x.Parameters)
    .Not.Inverse()     // 1
    .Not.KeyNullable() // 2
    .Not.KeyUpdate()   // 3
    .Access.BackingField()
    .KeyColumn("[Method]")
    .Not.LazyLoad()
    .Cascade.AllDeleteOrphan();

Please take a look at following answer for better explanation https://stackoverflow.com/a/7601312/259946 and https://stackoverflow.com/a/11576097/259946

Upvotes: 1

Related Questions