What code need to go here:
,ConventionBuilder.HasMany.Always(x =>
x.Key.Column( /* what code need to go here? */ ))
Aside from making this…
public virtual Person Owner { get; set; }
…to(which is ideal only on greenfield systems):
public virtual Person Person { get; set; }
How can I prevent NHibernate from producing the extraneous Person_id in its DDL creation?
Note the Person_id was produced by NH(or FNH?) even there’s already an owner_ref, and note the two references:
create table contact (contact_id int4 not null,
number text, type text, owner_ref int4,
Person_id int4, primary key (contact_id));
create table person (person_id int4 not null, person_name text not null, birthdate timestamp not null, primary key (person_id));
alter table contact
add constraint FK38B7242018FA494F
foreign key (owner_ref) references person;
alter table contact
add constraint FK38B724202B329A0D
foreign key (Person_id) references person;
I tried this just to make sure that it’s feasible to prevent extraneous reference
,ConventionBuilder.HasMany.Always(x => x.Key.Column("owner_ref"))
Here’s NHibernate DDL Creation when I add that ConventionBuilder:
create table contact (contact_id int4 not null, number text, type text,
owner_ref int4, primary key (contact_id));
create table person (person_id int4 not null, person_name text not null, birthdate timestamp not null, primary key (person_id));
alter table contact
add constraint FK38B7242018FA494F
foreign key (owner_ref) references person;
Note there are no more Person_id field, and there’s only one references now, which is correct. So it prevent duplicate references, it’s possible, but what I still doesn’t know is how to change the KeyColumn’s name of the collection(IList<Contact>) under Person in ConventionBuilder
Another way is to just change the KeyColumn in ClassMap directly, prevents duplicate reference in contact table…
HasMany(x => x.Contacts).Inverse().KeyColumn("owner_ref");
…, achieved the same SQL as above, but it’s better if I can make it automatic on ConventionBuilder.
How can I tell NHibernate from producing two references? Here’s the mapping code (note this: public virtual Person Owner { get; set; }. It’s not Person Person { get; set; }
public class Person
{
public virtual int PersonId { get; set; }
public virtual string PersonName { get; set; }
public virtual DateTime Birthdate { get; set; }
public virtual IList<Contact> Contacts { get; set; }
}
public class Contact
{
public virtual Person Owner { get; set; }
public virtual int ContactId { get; set; }
public virtual string Number { get; set; }
public virtual string Type { get; set; }
}
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.PersonId);
Map(x => x.PersonName).Not.Nullable();
Map(x => x.Birthdate).Not.Nullable();
HasMany(x => x.Contacts).Inverse();
}
}
public class ContactMap : ClassMap<Contact>
{
public ContactMap()
{
References(x => x.Owner);
Id(x => x.ContactId).GeneratedBy.Sequence("contact_contact_id_seq");
Map(x => x.Number);
Map(x => x.Type);
}
}
What’s the right ConventionBuilder on that design pattern(“_ref” suffix for child table’s field referencing parent table). That potentially happen on brownfield systems too.
I have found(formulated) the solution. The key thing is we must setup the joining key on both ends of the entities, i.e. we must set it up on ConventionBuilder.HasMany and ConventionBuilder.References
The ConventionBuilder.References is a solved problem. It is the ConventionBuilder.HasMany.Always(x => that we need to come up with a way of traversing the referencing object(e.g. Owner) from the .ConventionBuilder.HasMany.Always code.
We must normalize the references based on Many-To-One mappings from ConventionBuilder.HasMany. Unfortunately the references property is in protected access in ClassMap. For this, we must extend the ClassMap, and use that extended class on our mappings, so we can traverse the references
Following is the solution I coded, check the code of NormalizeReference here: http://www.ienablemuch.com/2010/12/brownfield-system-problem-on-fluent.html