I'm working on migrating an application to NHibernate, and I'm using Fluent NHibernate. I'm running into an issue mapping a collection of value types to an aggregate root.
I have a PhoneNumber
value type that has a few properties — Number
, NumberType
, and Description
. There are a number of objects in my domain that have collections of phone numbers.
In the database (SQL 2008), these values are held in different tables. So I might have Customers
and CustomerPhoneNumbers
as well as Vendors
and VendorPhoneNumbers
. The phone number tables are identical except for the foreign key that relates them to their parent.
The problem is that I would like to use a simple PhoneNumber
value type without having to create CustomerPhoneNumber
and VendorPhoneNumber
types that have properties that relate them to their parent type, and I don't know how to accomplish that in NHibernate. Is this possible or do I need to change my domain objects to more closely match the underlying database schema?
UPDATE: A little more info
It looks like I'm having trouble even getting the basic map to work for retrieval. Here's a simplified example of what I have:public class CustomerMap : ClassMap<Customer>
{
public CustomerMap()
{
Table("Customers");
Id(x => x.Id);
Map(x => x.Name);
Component(x => x.Address);
HasMany(x => x.PhoneNumbers)
.KeyColumn("CustomerId")
.Cascade.All()
.Table("CustomerPhoneNumbers");
}
}
public class PhoneNumberMap : ClassMap<PhoneNumber>
{
public PhoneNumberMap()
{
Id(x => x.Id);
Map(x => x.Number, "PhoneNumber");
Map(x => x.PhoneNumberType);
Map(x => x.Description);
}
}
It looks like the SQL isn't being generated properly. When I try to look into a customer's PhoneNumbers list, I get an ADO error that reveals that NHibernate is looking for a table named PhoneNumber
.
It seems like it's not picking up the Table("CustomerPhoneNumbers")
part and is defaulting to a table named the same thing as the object. Yet I can't specify a Table in the PhoneNumberMap, because it'll be different depending on which aggregate root we're pulling for.
You can map the single object PhoneNumber to multiple tables using the entity-name mapping attribute. Sorry, no sample code - I do not use Fluent so I cannot help with that aspect. I could post sample hbm mappings if that would be helpful.
Entity-name basically replaces class name across the board. When you use entity-name you will also have to modify your session to accept a parameter to specify the entity name whenever you work with the objects via the session.
Documentation is here:
http://docs.jboss.org/hibernate/core/3.2/reference/en/html/mapping.html#mapping-entityname
EDIT Added hbm samples.
This maps a single object PhoneNumber to multiple tables
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="DomainModel.PhoneNumber, DomainModel"
table="PhoneNumberVendors" entity-name="PhoneNumberVendor">
<id name="_id" access="field" column="PhoneNumberId">
<generator class="assigned"/>
</id>
<property name= "...">
</class>
<class name="DomainModel.PhoneNumber, DomainModel"
table="PhoneNumberCustomers" entity-name="PhoneNumberCustomer">
<id name="_id" access="field" column="PhoneNumberId">
<generator class="assigned"/>
</id>
<property name= "...">
</class>
</hibernate-mapping>
Then to call for example an update on a PhoneNumber you modify the session syntax to the following so nhibernate knows which table to use:
_session.Update("PhoneNumberCustomer", myCustomerNumber)
You will have to figure out if Fluent even supports this, if so how to do it. If not you can always use hbm files for the PhoneNumber object.
精彩评论