I have an entity that is made up of properties from two different tables as I described here and I’m running into problems when I try to insert a new item. When inserting I need to only update the fields in one of the two tables. Using the ReadOnly() method, I’ve been able to get NHibernate to ignore most of the fields from [RegistrationField] on save. However, I can’t get it to not try to save a new entry into [RegistrationField] for the foreign key, even though an entry already exists for that key.
My mapping for the class is:
public class RegistrationFieldMap : ClassMap<RegistrationField>
{
public RegistrationFieldMap()
{
Table("AccountRegistrationField");
Id(r => r.ID).Column("RegistrationID");
Map(r => r.AccountID);
Map(r => r.DefaultValue);
Map(r => r.FieldID);
Map(r => r.IsRequired);
Map(r => r.Label);
Map(r => r.Priority);
Join("RegistrationField", t =>
{
t.Map(r => r.FieldType).ReadOnly();
t.Map(r => r.HtmlID).ReadOnly();
});
}
}
When I run my test to verify the mapping, NHibernate tries to run the following two SQL statements:
INSERT INTO AccountRegistrationField (
AccountID,
DefaultValue,
FieldID,
IsRequired,
Label,
Priority)
VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
select SCOPE_IDENTITY();
@p0 = 1 [Type: Int32 (0)],
@p1 = 'bar' [Type: String (4000)],
@p2 = 1 [Type: Int32 (0)],
@p3 = False [Type: Boolean (0)],
@p4 = 'bar' [Type: String (4000)],
@p5 = 1 [Type: Int32 (0)]
INSERT INTO RegistrationField (UserRegistrationField_id) VALUES (@p0);
@p0 = 12 [Type: Int32 (0)]
I only need it to run the first statement, since the [RegistrationField] table contains a static list of values and new items should never be added to it.
Any and all suggestions welcome.
OK, after thinking about Diego’s comment and getting a good nights sleep I figured out the correct way to implement this and get the result I want. Diego is right that I should be using
Referenceand notJoin. My original reasoning for wanting to implement this as a join was a desire to avoid adding another level to my object graph.AccountRegistrationFieldis already a property on theAccountobject and I didn’t want to have to make a call likeAccount.AccountRegistrationField.RegistrationField.FieldType. I instead wanted the call to beAccount.AccountRegistrationField.FieldTypesince the object I’ll really be operating on is theAccountRegistrationFieldobject.I was able to get this behavior by designing my
AccountRegistrationFieldclass a little better. I made theRegistrationFieldproperty private and added public properties on theAccountRegistrationFieldclass to expose the fields that I needed. And then used Fluent NHibernate’s Reveal class to expose the private property to my mapping.My
AccountRegistrationFieldclass ended up looking like this:And my mapping for
AccountRegistrationFieldlooks like: