Referencing components from a subclassMap - fluent-nhibernate-mapping

I am trying to reference a component from a subclass map but am getting the following exception
"Visitor attempted on unresolved componented reference 'Weight', referenced from property 'Weight' of 'RecipeFermentable', unable to continue."
public class RecipeFermentableMap : SubclassMap<RecipeFermentable>
{
public RecipeFermentableMap()
{
Map(x => x.Pppg);
Component(x => x.Weight);
References(x => x.Recipe);
}
}
This work when I do it with a normal ClassMap but stopped working after re-factoring into a SubclassMap.

Related

Deletion of one-to-zero or one child record not working

I'm trying to map a couple of tables where the primary key in Bar is a foreign key to Foo i.e. a 1..0:1 relationship.
My mappings look like this:
class FooMapping : ClassMap<Foo>
{
public FooMapping()
{
Table("Foo");
Id(x => x.Id).Column("ID");
HasOne(x => x.Bar).Cascade.All();
}
}
class BarMapping : ClassMap<Bar>
{
public BarMapping()
{
Table("Bar");
Id(x => x.FooId).GeneratedBy.Foreign("Foo");
HasOne(x => x.Foo).Constrained();
}
}
The problem is that when I try to remove an instance of Bar by setting Foo.Bar = null and Bar.Foo = null, the record does not get deleted from the database.
What am I missing?
So basicly the problem is that you're using Cascade.All() in the mapping of Foo.
Instead of that you should be using Cascade.AllDeleteOrphan().
Cascade.All
when an object is save/update/delete, check the associations and save/update/delete all the objects found.
Cascade.AllDeleteOrphan
when an object is save/update/delete, check the associations and save/update/delete all the objects found. In additional to that, when an object is removed from the association and not associated with another object (orphaned), also delete it.
There is other dirty solution by making this relation with using HasMany and Cascade.AllDeleteOrphan.
class FooMapping : ClassMap<Foo>
{
public FooMapping()
{
Table("Foo");
Id(x => x.Id).Column("ID");
HasMany(x => x.Bar).KeyColumn("FooId").Cascade.AllDeleteOrphan();
}
}

Fluent Nhibernate ClassMaps and Column Order

Our entities have a group of common properties. In order to reduce repetitive mapping, I created a base ClassMap that maps the identities and common properties. For each entity's ClassMap I just subclass the base and it works great. For a new project we are also letting NH generate the DB schema for us. The issue is, the order of the columns is such that the properties from the base ClassMap appear first, followed by anything mapped in the sub class. The requirement for this build is that the columns appear in a specific order.
To get around this I did the following.
public class BaseMap<T> : ClassMap<T> where T : Entity
{
public BaseMap()
{
Id(x => x.Id);
MapEntity();
Map(x => x.CommonProperty1);
Map(x => x.CommonProperty2);
Map(x => x.CommonProperty3);
}
protected virtual void MapEntity()
{
}
}
public class SomeEntityMap : BaseMap<SomeEntity>
{
public SomeEntity()
{
base.MapEntity();
}
protected override void MapEntity()
{
Map(x => x.SomeEntityProperty1);
Map(x => x.SomeEntityProperty2);
Map(x => x.SomeEntityProperty3);
}
}
This works, but feels like a hack. Aside from the hack factor, is there anything here that could be problematic?
If you made the base class and map method abstract it would feel less hacky...
public abstract class BaseMap<T> : ClassMap<T> where T : Entity
{
public BaseMap()
{
Id(x => x.Id);
MapEntity();
Map(x => x.CommonProperty1);
Map(x => x.CommonProperty2);
Map(x => x.CommonProperty3);
}
protected abstract void MapEntity();
}
public class SomeEntityMap : BaseMap<SomeEntity>
{
protected override void MapEntity()
{
Map(x => x.SomeEntityProperty1);
Map(x => x.SomeEntityProperty2);
Map(x => x.SomeEntityProperty3);
}
}
This would keep the common property columns at the end of the table. Be aware that foreign key columns will still get added after those. I don't think there is any way to have full control of the column order w/ fluent, unless you hand-modify the create schema scripts.
I just had to implement something similar myself.
Assuming that you have
public class SomeEntity : Entity
{
...
}
A less 'hack-like' way would be:
public abstract class BaseMap<T> : ClassMap<T> where T : Entity
{
public BaseMap()
{
Id(x => x.Id);
Map(x => x.CommonProperty1);
Map(x => x.CommonProperty2);
Map(x => x.CommonProperty3);
}
}
public class SomeEntityMap : BaseMap<SomeEntity>
{
public SomeEntity()
{
Map(x => x.SomeEntityProperty1);
Map(x => x.SomeEntityProperty2);
Map(x => x.SomeEntityProperty3);
}
}
Same result in the end, but your not using overridden methods to add mappings. It'll be taken care of automagically.

NHibernate explicit fluent column mapping

I have a set of fluent object mappings that looks like this:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Map(x => x.Id);
Map(x => x.Status);
}
}
public class SpecialUserMap : SubClassMap<SpecialUser>
{
public SpecialUserMap()
{
Map(x => x.Property);
}
}
public class DirectoryMap : ClassMap<Directory>
{
public DirectoryMap
{
Map(x => x.Id);
HasMany(x => x.SpecialUsers).Where("Status = 0");
}
}
User is a join table, which SpecialUser joins against to get things like status. However, when I try to reference a SpecialUser in Directory's SpecialUsers collection, I get an error of "Undefined column 'Status'", as in the generated SQL, NHibernate tries to grab the Status column from the SpecialUser table, and not the User table.
Is there a way to explicitly tell NHibernate which table to get the Status column in the DirectoryMapping?
The Status property of a User / SpecialUser needs to map onto a single column in the database. You can't have it coming sometimes from User and sometimes from SpecialUser.
As a workaround, you could add a SpecialUserStatus property to SpecialUser, and then you could query on that easily.
That mappings looks right for table-per-subclass mapping, assuming that SpecialUser extends User. My guess is that it's a bug.

Fluent nhibernate map subclass in rc

I compiled the fluent nhibernate 1.0 rc with nhibernate 2.1 and had several warnings after the errors were fixed.
Fluent nhibernate tells me to use a separate Subclass-map instead of JoinedSubclass.
Current Mapping:
public class ClientMap : ClassMap<Client>
{
public ClientMap()
{
LazyLoad();
Id(x => x.Id);
//some boring stuff in between
JoinedSubClass<Company>("Id", m =>
{
m.LazyLoad();
m.Map(x => x.Name);
m.Map(x => x.Form);
});
}
The classes are inherited (company : client).
I tried the new mapping as follows:
public class CompanyMap : SubclassMap<Company>
{
CompanyMap()
{
LazyLoad();
Map(x => x.Name);
Map(x => x.Form);
}
}
After this change I don't get any companies, I'm not sure about how hibernate correctly knows what to do. Before I sayd "look, I have this class and the subclass I give you straight away in your mapping" and now: "Here are two mappings, figure by yourself, thx" :)
Any advices how to get the new subclass-mapping corrected?
Update:
Now I figured out that this works for saving data but the fk ID is not written to the child. How do I map the FK? The field name is Client_id, as nhibernate expects fk field names..

Fluent NHibernate table-per-class-hierarchy need to use .Where()?

I have the following mapping for a set of contact classes based off an abstract Contact class implementation.
public class ContactMapping : ClassMap<Contact> {
public ContactMapping() {
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.CreatedDate).Not.Nullable();
Map(x => x.Value).Not.Nullable();
Map(x => x.Level).Not.Nullable();
Map(x => x.Comments);
DiscriminateSubClassesOnColumn("ContactType");
}
}
public class PhoneContactMapping : SubclassMap<PhoneContact> {
public PhoneContactMapping() {
Map(p => p.PhoneType);
DiscriminatorValue("PhoneContact");
}
}
public class EmailContactMapping : SubclassMap<EmailContact> {
public EmailContactMapping() {
DiscriminatorValue("EmailContact");
}
}
public class WebsiteContactMapping : SubclassMap<WebsiteContact> {
public WebsiteContactMapping() {
DiscriminatorValue("WebsiteContact");
}
}
I have an entity class that HasMany EmailContact(s), WebsiteContact(s), and PhoneContact(s).
public class ContactableEntityMapping: ClassMap<ContactableEntity> {
public ContactableEntityMapping() {
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.CreatedDate).Not.Nullable();
Map(x => x.Comment);
HasMany<EmailContact>(x => x.EmailContacts).AsBag().Not.LazyLoad().Where("ContactType='EmailContact'");
HasMany<PhoneContact>(x => x.PhoneContacts).AsBag().Not.LazyLoad().Where("ContactType='PhoneContact'");
HasMany<WebsiteContact>(x => x.WebsiteContacts).Not.LazyLoad().AsBag().Where("ContactType='WebsiteContact'");
HasManyToMany(x => x.Addresses).AsSet();
}
}
If i do not specify there .Where() clauses the class ends up coming back with all rows mapped to EmailContact (since it is first in the listing) if LazyLoading is used, and if lazy-loading is not used I receive an exception as it attempts to cast the classes to the wrong type.
Obviously this is because the SQL executed is not passing in the additional where clause unless I specify it in the mapping. Am I missing something in my mapping, or is the Where mess just something we need to live with?
Thanks for the help!