NHibernate issue : persistent class not known - nhibernate

I have two tables Person and PassportInfo with a structure as given below:
Table Person
(
PersonID uniqueidentifier not null, (PK)
Name varchar(100) not null,
Email varchar(100) not null
)
Table PassportInfo
(
ID int identity(1,1) not null Primary Key,
personID uniqueidentifier null, (FK to PersonID in Person table)
PassportNumber varchar(100) not null
)
Also this is the mapping for Person
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Project" namespace="Project">
<class name="classperson" table="Person" >
<id name="ID" type="System.Guid" column="personID">
<generator class="Guid"/>
</id>
<property name="Name" column="Name" type="System.String" length="100" not-null="true" />
<property name="Email" column="Email" type="System.String" length="100" not-null="true" />
<one-to-one name="classpassportinfo" class="classpassportinfo" constrained="true" />
</class>
</hibernate-mapping>
This is the mapping for PassportInfo
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Project" namespace="Project">
<class name="classpassportinfo" table="PassportInfo" >
<id name="ID" type="System.Int32" column="ID">
<generator class="identity"/>
</id>
<property name="PassportNumber" column="PassportNumber" type="System.String" length="100" not-null="true" />
<one-to-one name="classperson" class="classperson" />
</class>
</hibernate-mapping>
This is the Object Class for Person
namespace Project
{
[Serializable]
public class classperson : Base<System.Guid>
{
private System.String _Name;
private System.String _Email;
private classpassportinfo _classpassportinfo;
public classperson()
{
}
public classperson(System.Guid id)
{
base.ID = id;
}
public virtual System.String Name {
get { return _Name; }
set { _Name = value;}
}
public virtual System.String Email {
get { return _Email; }
set { _Email = value;}
}
public virtual classpassportinfo classpassportinfo {
get { return _classpassportinfo; }
set { _classpassportinfo = value;}
}
}
}
Finally this is the object class for PassportInfo
namespace Project
{
[Serializable]
public class classpassportinfo :Base<Systme.Int32>
{
private System.String _PassportNumber;
private classpassportinfo _classpassportinfo;
public classpassportinfo()
{
}
public classpassportinfo(System.Int32 id)
{
base.ID = id;
}
public virtual System.String PassportNumber {
get { return _PassportNumber; }
set { _PassportNumber = value;}
}
public virtual classperson classperson {
get { return _classperson; }
set { _classperson = value;}
}
}
}
When I execute above code, i am getting and error saying persistent class not known: Project.classpassportinfo. I am new to nhibernate. Any help in this appreciated.

To elaborate and clarify #Fran's comment for anyone else struggling with this problem...
For me, in Visual Studio this issue was resolved by:
Open the solution explorer (Project structure navigator)
Locate the mapping file passportinfo.hbm.xml
Right click and choose properties
Under the advanced tab, make sure "Build Action" is set to "Embedded Resource"
The issue should be resolved now. Good luck

Related

Cascade Save - StaleObjectStateException: Row was updated or deleted by another transaction

Having an issue with updating the NHibernate version. Current version is 3.3.1.4000 and trying to update to 4.
After updating the unit test which does save with cascade fails with:
NHibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [NHibernateTests.TestMappings.ProductLine#cdcaf08d-4831-4882-84b8-14de91581d2e]
The mappings:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTests" namespace="NHibernateTests.TestMappings">
<class name="Product" lazy="false" table="UserTest">
<id name="Id">
<generator class="guid"></generator>
</id>
<version name="Version" column="Version" unsaved-value="0"/>
<property name="Name" not-null="false"></property>
<property name="IsDeleted"></property>
<bag name="ProductLines" table="ProductLine" inverse="true" cascade="all" lazy="true" where="IsDeleted=0" >
<cache usage="nonstrict-read-write" />
<key column="UserId" />
<one-to-many class="ProductLine" />
</bag>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTests" namespace="NHibernateTests.TestMappings">
<class name="ProductLine" where="IsDeleted=0" lazy="false">
<cache usage="nonstrict-read-write" />
<id name="Id">
<generator class="guid"></generator>
</id>
<version name="Version" column="Version" unsaved-value="0"/>
<property name="IsDeleted"></property>
<many-to-one name="Product" class="Product" column="UserId" not-null="true" lazy="proxy"></many-to-one>
</class>
</hibernate-mapping>
Classes:
public class Product
{
public Guid Id { get; set; }
public int Version { get; set; }
public bool IsDeleted { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public IList<ProductLine> ProductLines { get; private set; }
public Product()
{
ProductLines = new List<ProductLine>();
}
}
public class ProductLine
{
public Guid Id { get; set; }
public int Version { get; set; }
public bool IsDeleted { get; set; }
public Product Product { get; set; }
}
The test:
[TestMethod]
public void CascadeSaveTest()
{
var product = new Product
{
Id = Guid.NewGuid(),
Name = "aaa",
IsActive = true
};
var productLine = new ProductLine
{
Id = Guid.NewGuid(),
Product = product,
};
product.ProductLines.Add(productLine);
using (var connection = new RepositoryConnection())
{
using (var repositories = new Repository<Product>(connection))
{
repositories.Create(product);
//the below just calls the Session.Transaction.Commit();
connection.Commit(); //NH3.3.1.400 passes, NH4 fails
}
}
}
Thanks for you ideas in advance.
Well, I guess I have now understood what causes the error with NH 4. And If I am right, that is a bit contrived case causing this behavior to be hard to qualify as a bug.
In your example, products lines are mapped through a bag. A bag can contains duplicates, which requires an intermediate table between Product and ProductLine. (Something like a ProductProductLine table with an UserId (ProductId) column, and a ProductLineId column.)
You have set this intermediate table as being the ProductLine table. I suspect the commit to db causes NHibernate to insert the product, then the product line, then to try to insert the relationship by inserting again in ProductLine table. (You may check that by profiling SQL queries on your db.)
Things are a bit muddy, since doc states (emphasis is mine):
table (optional - defaults to property name) the name of the
collection table (not used for one-to-many associations)
But then, how to honor the bag semantics allowing duplicates in the collection? From the same doc:
A bag is an unordered, unindexed collection which may contain the same
element multiple times.
Anyway, within your example, you really should map your one-to-many with a set, as shown in doc.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTests" namespace="NHibernateTests.TestMappings">
<class name="Product" lazy="false" table="UserTest">
<id name="Id">
<generator class="guid"></generator>
</id>
<version name="Version" column="Version" unsaved-value="0"/>
<property name="Name" not-null="false"></property>
<property name="IsDeleted"></property>
<set name="ProductLines" inverse="true" cascade="all" lazy="true" where="IsDeleted=0" >
<cache usage="nonstrict-read-write" />
<key column="UserId" />
<one-to-many class="ProductLine" />
</set>
</class>
</hibernate-mapping>
And change your collection type for using .Net fx 4 System.Collections.Generic.ISet<T>.
public ISet<ProductLine> ProductLines { get; private set; }
public Product()
{
ProductLines = new HashSet<ProductLine>();
}
If this causes your trouble to disappear, it would mean something has changed in bag handling in NH 4. But should we consider this change as being a bug? Not sure, since using a bag in this case does not look right for me.
Drilling it further down turned out that NHibernate4 has problems identifying whether it is a new entity or an already existent when concerned with Cascade.
With the scenario in question it was calling a SQL Update for the ProductLine, rather than Create.
It works fine with the below changes, however I'm quite puzzled with such a changes in between NHibernate versions.
Change to ProductLine Mapping
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTests" namespace="NHibernateTests.TestMappings">
<class name="ProductLine" where="IsDeleted=0" lazy="false">
<cache usage="nonstrict-read-write" />
<!-- here comes the updated line -->
<id name="Id" type="guid" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid"></generator>
</id>
<version name="Version" column="Version" unsaved-value="0"/>
<property name="IsDeleted"></property>
<many-to-one name="Product" class="Product" column="UserId" not-null="true" lazy="proxy"></many-to-one>
</class>
</hibernate-mapping>
Change to test method
[TestMethod]
public void CascadeSaveTest()
{
var product = new Product
{
Id = Guid.NewGuid(),
Name = "aaa",
IsActive = true
};
var productLine = new ProductLine
{
Id = Guid.Empty, //The updated line
Product = product,
};
product.ProductLines.Add(productLine);
using (var connection = new RepositoryConnection())
{
using (var repositories = new Repository<Product>(connection))
{
repositories.Create(product);
connection.Commit();
}
}
}

NHibernate composite id mapping issue, bi/uni-directional OneToMany, ManyToOne and ManyToMany

In my project all of entities have composite primary keys [systemId as long, deviceId as long, id as long]. Values filled manualy before I save the entity.
I'm using "code first" approach and to provide simplicity references NHibernate.Mapping.Attributes extension to define schema with attributes just like in Java based Hibernate.
All entities have an abstract base type which provides shared properties and functionality:
[Serializable]
public abstract class EntityBase
{
[CompositeId(0, Name = "id", ClassType = typeof(EntityId))]
[KeyProperty(1, Name = "systemId", Column = "restId")]
[KeyProperty(2, Name = "deviceId", Column = "deviceId")]
[KeyProperty(3, Name = "id", Column = "id")]
private EntityId id = new EntityId(); // this is a component, see below
[Property(Column = "isDeleted", NotNull = true)]
private bool deleted = false;
public EntityId Id
{
get { return id; }
set { id = value; }
}
public bool Deleted
{
get { return deleted; }
set { deleted = value; }
}
}
Behind the composite id there is a component, which represent the complex primary key:
[Serializable]
[Component]
public class EntityId
{
[Property(Column = "restId", NotNull = true)]
private long systemId = 0;
[Property(NotNull = true)]
private long deviceId = 0;
[Property(NotNull = true)]
private long id = 0;
public long SystemId
{
get { return systemId; }
set { systemId = value; }
}
public long DeviceId
{
get { return deviceId; }
set { deviceId = value; }
}
public long Id
{
get { return id; }
set { id = value; }
}
}
I definied two entities called OTMList and OTMItem which have bi-directional OneToMany and ManyToOne associations to each other.
[Serializable]
[Class]
public class OTMList : EntityBase
{
[List(0, Cascade = "none", Generic = true, Lazy = CollectionLazy.True)]
[Key(1, Column = "id")]
[Index(2, Column = "id")]
[OneToMany(3, NotFound = NotFoundMode.Exception, ClassType = typeof(OTMItem))]
private IList<OTMItem> otmItems = new List<OTMItem>();
public IList<OTMItem> OTMItems
{
get { return otmItems; }
set { otmItems = value; }
}
}
[Serializable]
[Class]
public class OTMItem : EntityBase
{
[ManyToOne(0, Name = "otmList", ClassType = typeof(OTMList), Column = "OTMListId", Cascade = "none", Lazy = Laziness.Proxy)]
private OTMList otmList = null;
public OTMList OTMList
{
get { return otmList; }
set { otmList = value; }
}
}
The hibernate mapping xml file contains the following information:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping default-access="field" auto-import="true" assembly="NHibernateTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateTest.ListTest.OTM.OTMList, NHibernateTest">
<composite-id class="NHibernateTest.Domain.EntityId, NHibernateTest" name="id">
<key-property name="systemId" column="restId" />
<key-property name="deviceId" column="deviceId" />
<key-property name="id" column="id" />
</composite-id>
<property name="deleted" column="isDeleted" not-null="true" />
<list name="otmItems" lazy="true" cascade="none" generic="true">
<key column="id" />
<index column="id" />
<one-to-many class="NHibernateTest.ListTest.OTM.OTMItem, NHibernateTest" not-found="exception" />
</list>
</class>
<class name="NHibernateTest.ListTest.OTM.OTMItem, NHibernateTest">
<composite-id class="NHibernateTest.Domain.EntityId, NHibernateTest" name="id">
<key-property name="systemId" column="restId" />
<key-property name="deviceId" column="deviceId" />
<key-property name="id" column="id" />
</composite-id>
<property name="deleted" column="isDeleted" not-null="true" />
<many-to-one name="otmList" class="NHibernateTest.ListTest.OTM.OTMList, NHibernateTest" column="OTMListId" cascade="none" lazy="proxy" />
</class>
</hibernate-mapping>
When I validate the schema with SchemaValidator of the NHibernate I get the following exception:
Foreign key (FKF208BF0B9A2FCB3:OTMItem [OTMListId])) must have same number of columns as the referenced primary key (OTMList [restId, deviceId, id])
The problem are the same too when I try to create uni-directional ManyToOne or bi/uni-directional ManyToMany associations.
Somebody can help me please?
The full source code available here:
NHibernateTest source code
The problem is solved, check this out:
http://jzo001.wordpress.com/category/nhibernate/

Nhibernate one-to-one mapping

Hello guys I've tried searching for a solution to this problem for a period of time. Couldn't find it.
I have two classes which I will simplify. My problem is that i want a unidirectional one-to-one mapping between Player and Clan. Now I saw examples which have foreign key in ther id. But I don't understand it. This mapping is not producing a column in my Clans table for ClanLeader... Am i missing something? Thank you all for help.
public class Clan{
private Int32 id;
public virtual Int32 Id
{
get { return id; }
set { id = value; }
}
private string name;
public virtual string Name
{
get { return name; }
set { name = value; }
}
private Player clanLeader;
public virtual Player ClanLeader
{
get { return clanLeader; }
set { clanLeader = value; }
}
}
Then we have mapping for Clan:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernateSQLite"
namespace="NHibernateSQLite" >
<class name="GamingOrganizerDomainModel.Clan, GamingOrganizerDomainModel" table="Clans" lazy="false">
<id name="id" access="field" column="Clan_ID" type="Int32">
<generator class="native"></generator>
</id>
<property name="Name" column="Clan_Name" unique-key="ClanNameConstraint" type="String"/>
<one-to-one name="ClanLeader" class="GamingOrganizerDomainModel.Player, GamingOrganizerDomainModel" />
</class>
</hibernate-mapping>
Next is the class Player:
public class Player{
private Int32 id;
public virtual Int32 Id
{
get { return id; }
set { id = value; }
}
private string nickname;
public virtual string Nickname
{
get { return name; }
set { name = value; }
}
}
And mapping for Player:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernateSQLite"
namespace="NHibernateSQLite" >
<class name="GamingOrganizerDomainModel.Player, GamingOrganizerDomainModel" table="Players" lazy="false">
<id name="id" column="Player_ID" access="field" type="Int32">
<generator class="native" />
</id>
<property name="nickname" access="field" column="Nickname"/>
</class>
</hibernate-mapping>
Unidirectional one to one relation should be mapped as "many-to-one" element. "one-to-one" is used for bidirectional one to one. See this post for more details. Howerver there are ConfORM mappings as well the article is crystal clear.
You need make only one change in your Clan mapping:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="GamingOrganizerDomainModel"
namespace="GamingOrganizerDomainModel" >
<class name="Clan" table="Clans" lazy="false">
<id name="id" access="field" column="Clan_ID" type="Int32">
<generator class="native"></generator>
</id>
<property name="Name" column="Clan_Name" unique-key="ClanNameConstraint" type="String"/>
<many-to-one name="ClanLeader" class="Player" />
</class>
You do not need to write assembly qualified class name in the mapping. Assembly and namespace attributes of hibernate-mapping element specify default namespace and assembly where NH tries to find specific class.

Getting started with NHibernate

I am trying to develop my Hello World program in NHibernate.
My codes are as follows:
MyClass.cs
----------
using System.Collections.Generic;
using System.Text;
using System;
using NHibernate.Collection;
using NHibernate.Mapping;
using Iesi.Collections;
namespace NHibernate__MyClass
{
public class MyClass
{
int id;
string name;
int _value;
public MyClass()
{
id = 0;
name = "";
_value = 0;
}
public virtual int Id
{
get { return id; }
set { id= value; }
}
public virtual string Name
{
get { return name; }
set { name= value; }
}
public virtual int Value
{
get { return _value; }
set { _value= value; }
}
}
}
MyClass.hbm.xml
---------------
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernate__MyClass" assembly="NHibernate__MyClass">
<class name="MyClass" table="MyClass">
<id name="Id">
<column name="ID" sql-type="int" not-null="true"/>
<generator class="native" />
</id>
<property name="Name">
<column name="Name" not-null="true" />
</property>
<property name="Value">
<column name="Value" not-null="true" />
</property>
</class>
</hibernate-mapping>
Program.cs
----------
using System;
using System.Collections.Generic;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
namespace NHibernate__MyClass
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.Id = 1;
myClass.Name = "Hello World!";
myClass.Value = 100;
ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
ISession session = sessionFactory.OpenSession();
session.BeginTransaction();
session.Save(myClass);
session.Transaction.Commit();
Console.ReadLine();
}
}
}
App.config
----------
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="hibernate-configuration"
type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"
/>
</configSections>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.connection_string">Data Source=.\SQLEXPRESS;Initial Catalog=NHibernate;Integrated Security=True</property>
<mapping assembly="NHibernate__MyClass" />
</session-factory>
</hibernate-configuration>
</configuration>
SQL Table
---------
CREATE TABLE [dbo].[MyClass](
[ID] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[value] [int] NOT NULL
) ON [PRIMARY]
But this program is generating an Exception:
Exception message : {"could not insert: [NHibernate__MyClass.MyClass][SQL: INSERT INTO MyClass (Name, Value) VALUES (?, ?); select SCOPE_IDENTITY()]"}
Inner Exception Message : {"Cannot insert the value NULL into column 'ID', table 'NHibernate.dbo.MyClass'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}
What can be the problem?
NHibernate DLL version = 2.0.0.2002
Because of this tag in your mapping file
<generator class="native" />
In SQL you need to set the ID field in that table to an identity.
You can alternatively have nHibernate generate identity fields.

Doubly connected ordered tree mapping using NHibernate

We need to map simple class using NHibernate:
public class CatalogItem
{
private IList<CatalogItem> children = new List<CatalogItem>();
public Guid Id { get; set; }
public string Name { get; set; }
public CatalogItem Parent { get; set; }
public IList<CatalogItem> Children
{
get { return children; }
}
public bool IsRoot { get { return Parent == null; } }
public bool IsLeaf { get { return Children.Count == 0; } }
}
There are a batch of tutorials in the internet on this subject, but none of them cover little nasty detail: we need order to be preserved in Children collection. We've tried following mapping, but it led to strange exeptions thrown by NHibernate ("Non-static method requires a target.").
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Domain.Model" assembly="Domain">
<class name="CatalogItem" lazy="false">
<id name="Id" type="guid">
<generator class="guid" />
</id>
<property name="Name" />
<many-to-one name="Parent" class="CatalogItem" lazy="false" />
<list name="Children" cascade="all">
<key property-ref="Parent"/>
<index column="weight" type="Int32" />
<one-to-many not-found="exception" class="CatalogItem"/>
</list>
</class>
</hibernate-mapping>
Does anyone have any thoughts?
I'm no expert, but <key property-ref=...> looks strange to me in this usage. You should be able to do <key column="ParentID"/>, and NHibernate will automatically use the primary key of the associated class -- itself, in this case.
You may also need to set the list to inverse="true", since the relationship is bidirectional. [See section 6.8 in the docs.]