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.
Related
I'm trying to map a very basic parent-child relation with Fluent NHibernate.
However, when analyzing the SQL, only the parent-INSERT statement is created.
The situation is a simple class with a list of other classes. No relation back to the parent is needed. The children needs to be inserted/updated when the parent is inserted/updated.
var room = new Room();
room.Name = "Room1";
room.Courses.Add(new Course(){ Name = "Course1"});
room.Courses.Add(new Course(){ Name = "Course2"});
using (var session = sessionFactory.OpenStatelessSession())
{
using (var transaction = session.BeginTransaction())
{
session.Insert(room);
transaction.Commit();
}
}
The mapping looks like this.
public class RoomMapping : ClassMap<Room>
{
public RoomMapping()
{
Table("Rooms");
Id(x => x.Id)
.GeneratedBy.SeqHiLo("seq_rooms", "1000");
Map(x => x.Name);
HasMany(x => x.Courses)
.Cascade.All();
}
}
public class CourseMap : ClassMap<Course>
{
public CourseMap()
{
Table("Courses");
Id(x => x.Id)
.GeneratedBy.SeqHiLo("seq_courses", "1000");
Map(x => x.Name);
}
}
I already played with multiple options of the HasMany, however non with any success.
Sorry people. I just found it out.
I'm working in a Stateless session. So no relationships are managed ;)
I've got an application talking to two databases, and it runs fine, and my tests pass, except when it tries to export the current DB schema, it outputs everything for both DBs in one block, and when it tries to validate the object model / DB schema line up, it tries to look in one database for everything, when one class (which is external data, hence the foreign DB) should not be mapped. I provided a mapping override for the class so that NH can correctly load/use data from the foreign DB (it's read-only), but now when I export my schema, it tries to make that table.
I tried IgnoreBase(typeof(Unit)) but this has no effect (whereas IgnoreBase(typeof(Entity)) does work correctly). I have decorated the custom repository methods with [SessionFactory(DataGlobals.FOREIGN_DB_FACTORY_KEY)] where that simply defines a constant string to use as a key for the SessionFactory, but I'm sure if there's something I need to decorate the class (Unit) with or pass a different parameter to SchemaExport ...
public void CanGenerateDatabaseSchema(){
var session = NHibernateSession.GetDefaultSessionFactory().OpenSession();
using (TextWriter stringWriter = new StreamWriter("../../../../db/schema/UnitTestGeneratedSchema.sql"))
{
new SchemaExport(configuration).Execute(true, false, false, session.Connection, stringWriter);
}
}
public void CanConfirmDatabaseMatchesMappings()
{
var allClassMetadata = NHibernateSession.GetDefaultSessionFactory().GetAllClassMetadata();
foreach (var entry in allClassMetadata)
{
NHibernateSession.Current.CreateCriteria(entry.Value.GetMappedClass(EntityMode.Poco))
.SetMaxResults(0).List();
}
}
In Fluent NHibernate you can use SchemaAction.None to disable the generation of the schema for a particular table.
Example:
public class BankInfoMap : ClassMap<BankInfo>
{
public BankInfoMap()
{
Schema(“viplookups.dbo”);
Table(“bnkroute”);
SchemaAction.None();
Id(x => x.Id).Column(“bnkrouteid”);
Map(x => x.AbaNumber).Column(“crouting”);
Map(x => x.Name).Column(“ccompname”);
Map(x => x.City).Column(“ccity”);
Map(x => x.State).Column(“cstate”);
Map(x => x.PhoneNumber).Column(“cphone1″);
}
}
Taken from: http://lostechies.com/rodpaddock/2010/06/29/using-fluent-nhibernate-with-legacy-databases/
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 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.
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..