Reputation: 6995
EDIT: for the tl;dr crowd, my question is: How do I access the mappings from inside the ForeignKeyConvention in order to determine the table name that a given type is mapped to?
The long version:
I am using Fluent NHibernate to configure NHibernate, and I have a custom foreign key convention that is failing when I alias tables and columns.
My tables use a convention where the primary key is always called "PK", and the foreign key is "FK" followed by the name of the foreign key table, e.g., "FKParent". For example:
CREATE TABLE OrderHeader (
PK INT IDENTITY(1,1) NOT NULL,
...
)
CREATE TABLE OrderDetail (
PK INT IDENTITY(1,1) NOT NULL,
FKOrderHeader INT NOT NULL,
...
)
To make this work, I've built a custom ForeignKeyConvention that looks like this:
public class AmberForeignKeyConvention : ForeignKeyConvention
{
protected override string GetKeyName( Member member, Type type )
{
if ( member == null )
return "FK" + type.Name; // many-to-many, one-to-many, join
return "FK" + member.Name; // many-to-one
}
}
This works so long as my entities are named the same as the table. But it breaks when they aren't. For example, if I want to map the OrderDetail table to a class called Detail, I can do so like this:
public class DetailMap : ClassMap<Detail>
{
public DetailMap()
{
Table( "OrderDetail" );
Id( o => o.PK );
References( o => o.Order, "FKOrderHeader" );
...
}
}
The mapping works for loading a single entity, but when I try to run any kind of complicated query with a join, it fails, because the AmberForeignKeyConvention class is making incorrect assumptions about how the columns are mapped. I.e., it assumes that the foreign key should be "FK" + type.Name, which in this case is Order, so it calls the foreign key "FKOrder" instead of "FKOrderHeader".
So as I said above: My question is, how do I access the mappings from inside the ForeignKeyConvention in order to determine a given type's mapped table name (and for that matter, their mapped column names, too)? The answer to this question seems to hint at the right direction, but I don't understand how the classes involved work together. When I look through the documentation, it's frightfully sparse for the classes I've looked up (such as the IdMapping class).
Upvotes: 0
Views: 736
Reputation: 30813
the idea is to load the mappings
public class AmberForeignKeyConvention : ForeignKeyConvention
{
private static IDictionary<Type, string> tablenames;
static AmberForeignKeyConvention()
{
tablenames = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => typeof(IMappingProvider).IsAssignableFrom(t))
.ToDictionary(
t => t.BaseType.GetGenericArguments()[0],
t => ((IMappingProvider)Activator.CreateInstance(t)).GetClassMapping().TableName);
}
protected override string GetKeyName( Member member, Type type )
{
return "FK" + tablenames[type]; // many-to-one
}
}
Upvotes: 1