NHibernate mapping table of tables
I'm trying to wrap NHibernate around a legacy database (not created by me). It has what I can best describe as a "table of tables," called TABLE_DETAIL. It looks something like this:
COLUMN_NAME | TABLE_VALUE | TABLE_DESC
-------------+-----------------+---------------------------------
state | CA | California
state | NY | New York
...
countr开发者_StackOverflow中文版y | US | United States
country | CA | Canada
I'm trying to map this using Fluent NHibernate with the table-per-class-hierarchy strategy. In other words, I have a TableDetail class, and subclasses State and Country. I use the COLUMN_NAME as the discriminator.
TableDetailMap.cs:
public class TableDetailMap : ClassMap<TableDetail>
{
public TableDetailMap()
{
Table("TABLE_DETAIL");
CompositeId()
.KeyProperty(x => x.TableValue, "TABLE_VALUE")
.KeyProperty(x => x.ColumnName, "COLUMN_NAME");
Map(x => x.ColumnName).Column("COLUMN_NAME");
Map(x => x.TableDesc).Column("TABLE_DESC");
DiscriminateSubClassesOnColumn("COLUMN_NAME");
}
}
StateMap.cs:
public class StateMap : SubclassMap<State>
{
public StateMap()
{
DiscriminatorValue("state");
}
}
TABLE_DETAIL thus has a composite key (made up of COLUMN_NAME/TABLE_VALUE), and the discriminator is one of those fields. My problem is that NHibernate expects both components of the composite key to be referenced in another table - but they shouldn't need to be, because one is defined by the discriminator.
For example, I have the ADDRESS_RECORD table:
LINE_1 | CITY | STATE | ZIP
-----------------+-----------------+-----------+----------------
123 Any Street | Anytown | CA | 12345
The problem comes in when I try to map my "State" field to my State class. The STATE column in ADDRESS_RECORD refers to half of the TABLE_DETAIL primary key - the TABLE_VALUE part. The COLUMN_NAME part is "state" - because it's the discriminator, I'd expect that it should be provided. But NHibernate doesn't think so, and throws this exception:
Foreign key (FK3D33E87CA66E339C:ADDRESS_RECORD [STATE])) must have same number of columns as the referenced primary key (TABLE_DETAIL [TABLE_VALUE, COLUMN_NAME])
How can I map this so that NHibernate knows to automatically provide "state" as the value for the second half of the composite key?
If I can provide more information, please let me know.
I came up with a so-so fix. In the base class map (TableDetailMap.cs), where I specified the discriminator, I specified "always select with value", like so:
public class TableDetailMap : ClassMap<TableDetail>
{
public TableDetailMap()
{
...snip...
DiscriminateSubClassesOnColumn("COLUMN_NAME").AlwaysSelectWithValue();
}
}
Then, in all of the mapping classes that use a TableDetail object, I had to specify to use "select" when fetching, like so:
public class AddressRecordMap : ClassMap<AddressRecord>
{
public AddressRecordMap()
{
...snip...
References(x => x.State)
.Column("STATE")
.Fetch.Select();
...snip...
}
}
This still did not work in the case where I had one of these objects used as part of a composite ID. I'm not sure how to fix that, but I was able to work around it for now.
精彩评论