Make a Fluent NHibernate foreign key convention which includes parent key name

fluent-nhibernatenaming-conventions

I have a database schema where the convention for a foreign key's name is:

ForeignTable.Name + ForeignTable.PrimaryKeyName

So, for a Child table referencing a Parent table with a primary key column named Key, the foreign key will look like ParentKey.

Is there a way to create this convention in my Fluent NHibernate mapping?

Currently I'm using a ForeignKeyConvention implementation like this:

public class ForeignKeyNamingConvention : ForeignKeyConvention
{
    protected override string GetKeyName(PropertyInfo property, Type type)
    {
        if (property == null)
        {
            // Relationship is many-to-many, one-to-many or join.
            if (type == null)
                throw new ArgumentNullException("type");

            return type.Name + "ID";
        }

        // Relationship is many-to-one.
        return property.Name + "ID";
    }
}

This works exactly as I want for all types which have "ID" as a primary key. What I would like to do is replace the constant "ID" with the name of the primary key of the type being referenced.

If this isn't currently possible with Fluent NHibernate, I'm happy to accept that answer.

Best Answer

Take a look at conventions and especially at implementing a custom foreign key convention.


UPDATE:

Here's an example. Assuming the following domain:

public class Parent
{
    public virtual int Id { get; set; }
}

public class Child
{
    public virtual string Id { get; set; }
    public virtual Parent Parent { get; set; }
}

which needs to be mapped to this schema:

create table Child(
    Id integer primary key, 
    ParentId integer
)

create table Parent(
    Id integer primary key
)

you could use this convention:

public class CustomForeignKeyConvention : IReferenceConvention
{
    public void Apply(IManyToOneInstance instance)
    {
        instance.Column(instance.Class.Name + "Id");
    }
}

and to create the session factory:

var sf = Fluently
    .Configure()
    .Database(
        SQLiteConfiguration.Standard.UsingFile("data.db3").ShowSql()
    )
    .Mappings(
        m => m.AutoMappings.Add(AutoMap
            .AssemblyOf<Parent>()
            .Where(t => t.Namespace == "Entities")
            .Conventions.Add<CustomForeignKeyConvention>()
        )
    )
    .BuildSessionFactory();
Related Topic