NHibernate - mapping the generic entity that implements the tree structure - nhibernate

I am relatively new to using Nhibernate but basic things already are working.
Now I have to map the generic entity that implements the tree structure. Separately, each one (only generic or only tree) works fine.
Here's the code for the model:
public class Test<T>
{
public virtual Int64 Id { get; set; }
public string Name { get; set; }
public IList<Test<T>> Children { get; set; }
}
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="PersistencyObjectModel" namespace="PersistencyObjectModel.Domain">
<class name="Test`1[String]">
<id name="Id">
<generator class="guid"/>
</id>
<property name="Name" length="50" not-null="true" unique="true"/>
<set name="Children" table="TEST_TEST_LINK" cascade="all-delete-orphan" >
<key column="ParentId"/>
<many-to-many column="ChildId" class="Test`1[String]"/>
</set>
</class>
</hibernate-mapping>
When I use that model, I get the following Nhibernate error:
{"persistent class PersistencyObjectModel.Domain.Test`1[[PersistencyObjectModel.Domain.String,
PersistencyObjectModel]], PersistencyObjectModel not found"}
What does this error mean and how can I fix it?

Update: try this
<hibernate-mapping namespace="PersistencyObjectModel.Domain"
assembly="PersistencyObjectModel"
xmlns="urn:nhibernate-mapping-2.2">
<class name="PersistencyObjectModel.Domain.Test`1[[System.String,
mscorlib, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
table="TestOfString">
<id name="Id">
<generator class="guid.comb"/>
</id>
<property name="Name" length="50" not-null="true" unique="true"/>
<set name="Children" table="TEST_TEST_LINK">
<key column="ParentId" />
<many-to-many column="ChildId"
class="PersistencyObjectModel.Domain.Test`1[[System.String,
mscorlib, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089]]"/>
</set>
</class>
</hibernate-mapping>
Some things to note:
You can't use a guid generator with a long propery; change that to Guid
You must specify the name of the entity table
Use fully qualified names.

Related

facing issue while annotating below are both classes and Hbm.xml mentioned have tried different method but receiving exception

**
Below are both the class Conversion below Hbm.xml file with annotation
facing issue while annotating have tried different method but receiving exception
**
public class Parent {
private Set<Childaction>childactions=new HashSet<>();
}
public class Childaction extends parent {
private Parent main;
}
<hibernate-mapping>
<set name="childactions" table = "child table" cascade="save-update">
<key column="ID1"foreign-key="Foreignkey1"/>
<many-to-many column="Execute_id" unique="true" class="Childaction"/>
</set>
<subclass name="Childaction" extends="Parent" discriminator-value="not null">
<join table="childtable" inverse="true" optional="true">
<key column="Execute_id" foreign-key="foreignkey2"/>
<many-to-one name="main" column="ID1"not-null="true"/>
</join>
</subclass>
<filter name="main"/>
</class>
</hibernate-mapping>

NHibernate mapping not saving

I have the following Nhibernate XML file, edited to the core bits:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="TTP.DAO" namespace="TTP.DAO" xmlns="urn:nhibernate-mapping-2.2">
<class name="InitialProcessSetup" table="InitialProcessSetup" lazy="true" >
<id name="SetupID" column="setupID" unsaved-value="0" type="System.Int32">
<generator class="identity"/>
</id>
<property name="DateCreated" column="DateCreated" />
<many-to-one class="StoredUser" name="CreatedBy" column="CreatedBy" cascade="all-delete-orphan" not-null="true"/>
<property name="OriginalDeadline" column="Deadline" />
<property name="Detail" column="Detail" />
<bag name="Subjects" table="InitialProcessSetupRatingSubject" inverse="true" cascade="all-delete-orphan">
<key column="SetupId" not-null="true" />
<many-to-many column="SubjectStoredUserId" class="StoredUser" />
</bag>
<bag name="Reviewers" table="InitialProcessSetupReviewer" cascade="all-delete-orphan">
<key column="SetupId" not-null="true" />
<many-to-many column="ReviewerStoredUserId" class="StoredUser" />
</bag>
<bag name="Invitations" cascade="all-delete-orphan">
<key column="Setup" not-null="true"/>
<one-to-many class="ProcessInvitation" />
</bag>
</class>
I populate a new instance of the class indicated in the above mapping and save via GenericDAO().SaveOrUpdate(setup); and it saves the main object details but does not store the bit.
On the class Subjects is defined as a virtual property that returns IList-StoredUser. The class constructor sets this property to a new List-StoredUser-().
The table indicated by the Subjects bag element is a pure mapping table that is it has a SetupID and StoredUserID column and that's it.
I add using a StoredUser to my derived StoredUserDAO() to the Subjects lists before saving. After the call to SaveOrUpdate() I also call Flush() as well.
In my database (SQL Server 2008R2) The main setup data is saved and the stored user I added to the Subjects list property is also saved it's just the mapping table does not get the setupID/StoredUserID added.
I'm a bit of a noob with Nhibernate and this is an existing project.
Any help ideas on what is wrong would be most appreciated.
You have set inverse="true" for the Subjects collection. This implies that for NHibernate to create a record in the relation table, it must be the StoredUser that references the InitialProcessSetup.

NHibernate Mapping Exception: invalid child element

I'm having a problem with NHibernate and the mapping file when I try to save my drink object in my MVC application. My mapping file is an embedded resource and my hibernate.cfg.xml is copy always.
Here are my class.cs:
namespace FrancosPoS.DBMapping {
public class drink {
public drink() { }
public virtual int id { get; set; }
public virtual string type { get; set; }
public virtual string price { get; set; }
}
}
My XML mapping:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="FrancosPoS.DBMapping" namespace="FrancosPoS.DBMapping" xmlns="urn:nhibernate-mapping-2.2">
<class name="drink" table="drink" lazy="true" >
<id name="id">
<generator class="identity" />
<column name="id" sql-type="int(11)" not-null="true" />
</id>
<property name="type">
<column name="type" sql-type="varchar(25)" not-null="true" />
</property>
<property name="price">
<column name="price" sql-type="varchar(8)" not-null="true" />
</property>
</class>
</hibernate-mapping>
By the way, the connection opens and close fine if I don't try to save it on the database.
Here is my Solution Explorer:
Solution Explorer Image
And here is the error that is driving me nuts:
"Error: NHibernate.MappingException: FrancosPoS.DBMapping.drink.hbm.xml(6,8): XML validation error: The element 'id' in namespace 'urn:nhibernate-mapping-2.2' has invalid child element 'column' in namespace 'urn:nhibernate-mapping-2.2'. ---> System.Xml.Schema.XmlSchemaValidationException: The element 'id' in namespace 'urn:nhibernate-mapping-2.2' has invalid child element 'column' in namespace 'urn:nhibernate-mapping-2.2'.\r\n --- End of inner exception stack trace ---
the problem is in node id, it does not have a child, remove that node and it will simply be like this:
<id name="id">
<generator class="identity" />
</id>
the column's name is specified in id node, and you dont have to tell column has "not-null" constraint since id columns are always required
Also, in this line of your xml mapping:
<hibernate-mapping assembly="FrancosPoS.DBMapping" namespace="FrancosPoS.DBMapping" xmlns="urn:nhibernate-mapping-2.2">
"assembly" attribute seems to be wrong, it should be the name of your assembly (which i'm almost sure is "FrancosPos").

NHibernate One-To-One Relationships not saving correctly

I am having an issue with saving entities with one-to-one relationships. I just want to save the parent entity and have the child be save aswell but I am having to save both separately.
This is an example of what I am having to do, otherwise the child is not saved.
var session = SessionProvider.OpenSession.Session;
using (var tx = session.BeginTransaction())
{
try
{
session.SaveOrUpdate(parent);
if (parent.Child.IsPersisted)
{
session.Update(parent.Child);
}
else
{
session.Save(parent.Child);
}
}
}
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false" assembly="xxx">
<class name="Parent" polymorphism="explicit" table="Parent">
<id name="Id" column="JointID" type="int">
<generator class="native" />
</id>
<one-to-one name="Child" class="Child" />
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false"
assembly="xxx">
<class name="Child" xmlns="urn:nhibernate-mapping-2.2" polymorphism="explicit" table="Child">
<id name="Id" column="JointID" type="int" unsaved-value="0">
<generator class="native" />
</id>
<many-to-one name="Parent" column="JointID" insert="false" update="false" />
</class>
</hibernate-mapping>
Any ideas on how I can just make it save without having to do two save calls?
When I set the relationship to cascade as suggested below I get foreign key constraint errors. If I analyse the queries with NHProf, its trying to use the temporary id (-1) as the JointId in the insert statement rather than the newly created parent id. The JointId in the Parent table is an Identity key, perhaps that is an issue?
You'll need to enable cascading on your <one-to-one> mapping to have this work properly.
Something like:
<one-to-one name="Child" class="Child" cascade="save-update" />
You can read up on the various cascade settings here.

NHibernate Cascade none still updating related entity

I am then using Fluent NHibernate and its automapping feature to map the the following simplified POCO classes:
public class Webpage
{
public virtual int Id { get; set; }
public virtual string UrlIdentifier { get; set; }
public virtual WebpageType WebpageType { get; set; }
}
public class WebpageType
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
I am then overriding the following mapping to explicitly set no cascading from Webpage to WebpageType:
public class WebpageMap : IAutoMappingOverride<Webpage>
{
public void Override(AutoMapping<Webpage> mapping)
{
mapping.References(w => w.WebpageType).Cascade.None();
}
}
For any pur NHibernate readers, here are the xml mappings produced by fluent:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" name="EveryPage.Core.Domain.Webpage, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Webpage`">
<id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
<column name="Id" />
<generator class="identity" />
</id>
<property name="UrlIdentifier" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="UrlIdentifier" />
</property>
<many-to-one cascade="none" class="EveryPage.Core.Domain.WebpageType, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="WebpageType">
<column name="WebpageType_id" />
</many-to-one>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" name="EveryPage.Core.Domain.WebpageType, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`WebpageType`">
<id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
<column name="Id" />
<generator class="identity" />
</id>
<property name="Name" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Name" />
</property>
</class>
</hibernate-mapping>
The problem comes when I test that updates do not cascade to WebpageType via webpage, basically they do!!
I have the following test:
[Test]
public void Assert_SaveOrUpdate_On_Webpage_Does_Not_Cascade_Update_To_WebpageType()
{
// Get the existing webpage.
webpage = _webpageRepository.Get("~/testwebpage1.aspx");
// Update the WebpageType.
const string webpageTypeName = "qwerty test";
webpage.WebpageType.Name = webpageTypeName;
// Save the changes.
Assert.DoesNotThrow(() => _webpageRepository.SaveOrUpdate(webpage));
// We need to flush the changes to the store for it to execute the changes.
Assert.DoesNotThrow(() => NHibernateSession.Current.Flush());
// Remove the webpage and tag from the level 1 cache so we force a trip to the store on our next check.
NHibernateSession.Current.Evict(webpage);
// Check that the webpageType has not been updated.
webpageType = _webpageTypeRepository.Get(webpageType.Id);
Assert.AreNotEqual(webpageTypeName, webpageType.Name);
}
The above test is wrapped in a global transaction.
The test fails and NHibernate does execute an update to the Name of the related WebpageType. The delete and save(create new) cascades work correctly and do not cascade.
Have I missunderstood cascade and/or is there a problem with my logic/test.
Any help/advice is appreciated. Thanks.
If you are trying to stop your app from accidentally changing properties on WebPageType, I think it would be easier and safer to achieve this by marking WebPageType as ReadOnly in the mapping. Then you won't need to protect it via handling cascading in all its associations.
I think this is a misunderstanding of what cascading means.
In your example, NHibernate will update the Name property of you WebPageType no matter what you set cascading to. If you think about it, how would the NHibernate library tell if you're manipulating the property's value using the association from the WebPage instance, or if it's done "directly"?
The settings for cascading in NHibernate tells how associations between entities should be handled, not how the actual value inside each entity is handled. For example, you can set delete cascading, which will automatically delete associated entities when the entity itself is deleted.
Things blog post might make things a bit clearer, or at least work as some kind of reference: http://ayende.com/Blog/archive/2006/12/02/NHibernateCascadesTheDifferentBetweenAllAlldeleteorphansAndSaveupdate.aspx
What does your repository do? Make sure it doesn't run a saveorupdate on the webpagetype. If it isn't then I don't see any obvious explanation for this behaviour.