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.
Related
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();
}
}
I have an entity:
public class Foo
{
public virtual int Id;
public virtual IEnumberable<string> Bars;
}
And its mapping:
public class FooMapping : ClassMap<Foo>
{
public FooMapping()
{
Table("foo_table_in_database");
Id(x => x.Id, "Id");
HasMany(x => x.Bars)
.AsList()
.Table("bars_table_in_db")
.Element("BarId", m =>
{
m.Type<string>();
});
}
}
And an exception returned inside the entity insteaf of the expected result :(
base = {"could not initialize a collection: [Loya.Services.CouponsWeb.Promotion.LoyCouponCustomerGroups#2][SQL: SELECT loycouponc0_.Promotion_id as Promotion3_0_, loycouponc0_.LoyCustomerGroupId as LoyCusto1_0_, loycouponc0_.Index as Index0_ FROM loy_promotion__cu...
Database tables :
foo_table : *Id, other properties
bar_table : *FooId, *BarId
My aim is to get a List of BarId's (strings) in my Foo.
How do I map it properly?
I think you might need to specify the KeyColumn. I do something similar in one of my solutions and I would map the entities above as follows...
mapping.HasMany(x => x.Bars)
.Schema("Schema")
.Table("FooBars")
.Element("Bar")
.KeyColumn("FooID")
.ForeignKeyConstraintName("FK_FooBar_Foo")
.Not.Inverse()
.Cascade.All()
.Fetch.Select();
This will give a table called Schema.FooBars. It will have a FooID column (which is a foreign key back to the Foo table) and a Bar column which contains the value in your Bars collection.
I have Survey that HasMany Question that HasMany Option.
I want to create a reference from Option to Survey.
The problem is that Every time I want to create a new Survey with all of its children, I need to loop on all survey.Questions and loop on all survey.Questions.Options and set o each Option the Survey (or else Nhibernate will create a new Survey for each Option)
** I dont want to have IList<Option> on Survey if I do that it will solve the problem but it would be heavy and unusable **
public class SurveyMap : ClassMap<Survey>
{
public SurveyMap()
{
Id(x => x.Id).GeneratedBy.Identity();
HasMany(x => x.Questions).KeyColumn("SurveyId").Inverse().AsBag().Not.LazyLoad().Cascade.SaveUpdate();
}
}
public class QuestionMap : ClassMap<Question>
{
public QuestionMap()
{
Id(x => x.Id).GeneratedBy.Identity();
HasMany(x => x.Options).KeyColumn("QuestionId").Inverse().AsBag().Cascade.SaveUpdate();
}
}
public class OptionMap : ClassMap<Option>
{
public OptionMap()
{
Id(x => x.Id).GeneratedBy.Identity();
References(x => x.Survey).Column("SurveyId").Cascade.All();
}
}
It might be better to separate your reporting concerns from your applications business logic concerns. Use the mappings that you already have for your applications business logic, and provide a different interface into the data for your reporting requirements. You could use either HQL, SQL or new objects and maps for this.
Looking for some advice on how to update a collection on an entity. In a web app - we have a multiselect listbox allowing a user to assign and remove child entities from a list of available entities. The user would select the relevant children to associate with the parent. i.e. Product with multiple Categories it could belong to. Once the user is satisfied, they submit and we update the entities.
What is the preferred way to update(delete removed children, add new children) to the collection taking performance into account. I would not want to run several sql statements to fetch each child and add it to the parent.
Cheers
Mappings Attached:
public class ParentMap : EntityMapping<Parent>
{
public ParentMap()
{
Map(x => x.Name);
HasMany(x => x.Children)
.Cascade.AllDeleteOrphan()
.Access.LowerCaseField(Prefix.Underscore);
}
}
public class ChildMap : EntityMapping<Child>
{
public ChildMap()
{
References(x => x.Parent);
}
}
public abstract class EntityMapping<TEntity> : ClassMap<TEntity> where TEntity : EntityBase
{
protected EntityMapping()
{
Id(x => x.Id, "Id")
.UnsavedValue("00000000-0000-0000-0000-000000000000")
.GeneratedBy.GuidComb();
OptimisticLock.Version();
Version(entity => entity.Version);
}
}
Establish a cascade relation between parent and child entities and force it to act on all operations like update, delete, etc. You must define cascade behavior in you HBM mapping files. For more info: http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-mapping
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..