1
votes

I have the following entities in my domain model:

class Entity
{
    public int Id { get; set; }
}

class Foo : Entity
{
    public IDictionary<string, Attribute> Attributes { get; set; }
}

class Bar : Entity
{
    public IDictionary<string, Attribute> Attributes { get; set; }
}

class Attribute : Entity
{
    public string Key { get; set; }
    public string Value { get; set; }
    public IDictionary<string, Attribute> Attributes { get; set; }
}

I'd like to map these dictionaries with Fluent NHibernate. I've gotten most things to work, but first I'm having difficulties with the self-referencing Attribute.Attributes property. This is due to NHibernate making the Key a primary key of the Attribute table as well as the Id it inherits from Entity. This is how my mapping works:

ManyToManyPart<Attribute> manyToMany = mapping
    .HasManyToMany<Attribute>(x => x.Attributes)
    .ChildKeyColumn("AttributeId")
    .ParentKeyColumn(String.Concat(entityName, "Id"))
    .AsMap(x => x.Key, a => a.Column("`Key`"))
    .Cascade.AllDeleteOrphan();

if (entityType == typeof(Attribute))
{
    manyToMany
        .Table("AttributeAttribute")
        .ParentKeyColumn("ParentAttributeId");
}

If I replace the if statement with the following:

if (entityType == typeof(Attribute))
{
    manyToMany
        .Table("Attribute")
        .ParentKeyColumn("ParentAttributeId");
}

I get the following exception:

NHibernate.FKUnmatchingColumnsException : Foreign key (FK_Attribute_Attribute [ParentAttributeId])) must have same number of columns as the referenced primary key (Attribute [ParentAttributeId, Key])

This is due to NHibernate automatically making Key the primary key alongside Id in my Attribute column. I'd like Key to not be primary key, since it shows up in all of my many to many tables;

create table FooAttribute (
    FooId INT not null,
    AttributeId INT not null,
    [Key] NVARCHAR(255) not null
)

I'd like the foreign keys to only reference Id and not (Id, Key), since having Key as a primary key requires it to be unique, which it won't be across all of my ManyToManys.

1

1 Answers

1
votes
  • where do you map Attribute itself (does it contain a Composite Key)?
  • AttributeValue may be a better name to show that it contains a value.
  • .AsMap(x => x.Key) is enough to say that Key should be the dictionary key

    create table FooAttribute (
        FooId INT not null,
        AttributeValueId INT not null
    )
    

or consider using

mapping.HasMany(x => x.Attributes)
    .KeyColumn(entity + Id)
    .AsMap(x => x.Key)
    .Cascade.AllDeleteOrphan();

which will create

    create table Attribute (
        Id INT not null,
        FooId INT,
        BarId INT,
        ParentAttributeId INT,
        Key TEXT,
        Value TEXT,
    )