NHibernate.Mapping Exception. No persister for Namespace.className

4.8k views Asked by At

Have looked at 4 stackoverflow posts on the same issue but couldn't find a solution.

My main program:

using System;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Dialect;

namespace NhibernateORM
{
    public class Layout
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public double xCoordinate { get; set; }
        public double yCoordinate { get; set; }
    }
    class Program
    {
        private static int getDummyTableSize(ISession session)
        {
            ITransaction readTx = session.BeginTransaction();
            int size = session.CreateSQLQuery(@"select * from mydb.mytable").List<object>().Count;
            readTx.Rollback();
            return size;
        }

        static void Main(string[] args)
        {
            Configuration config = new Configuration();
            config.Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "hibernate.cfg.xml"));

            ISessionFactory factory = config.BuildSessionFactory();
            ISession session = factory.OpenSession();

            int countBefore = getDummyTableSize(session);

            ITransaction tx = session.BeginTransaction();
            Layout d = new Layout();
            d.Id = 213;
            d.Name = "hello";
            d.xCoordinate = 25.823;
            d.yCoordinate = 746.2;

            // POINT OF ERROR 
            session.Save(d);
            tx.Commit();

            if (countBefore + 1 == getDummyTableSize(session))
            {
                Console.WriteLine("woo hoo");
            }
            else
            {
                Console.WriteLine("oh no");
            }
            session.Close();
        }
    }
}

My hibernate.cfg.xml (config file):

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="connection.provider">
      NHibernate.Connection.DriverConnectionProvider
    </property>
    <property name="connection.driver_class">
      NHibernate.Driver.MySqlDataDriver
    </property>
    <property name="connection.connection_string">
      Server=localhost;Database=mydb;User="root";
    </property>
    <property name="dialect">
      NHibernate.Dialect.MySQL5Dialect
    </property>
    <!--<mapping assembly="NhibernateORM"/>-->
    <!-- mapping files -->
    <!--<mapping resource="Mapping.hbm.xml" />-->
  </session-factory>
</hibernate-configuration>

and my Mapping.hbm.xml file:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NhibernateORM" auto-import="true">
  <class name="Layout" table="mytable">
   <id name="Id" column="ID" type="int">
   </id> 
   <property name="Name" column="name" 
             type="String"></property>
  <property name="xCoordinate" column="xCoordinate" 
             type="double"></property>
<property name="yCoordinate" column="yCoordinate" 
             type="double"></property>
  </class>
</hibernate-mapping>

I tried the following:

  1. Set build action of mapping file(Mapping.hbm.xml) to embedded resource and build action of config file (hibernate.cfg.xml) to embedded resource and content. Also set copy to output directory to copy always.

  2. Set auto-import in hibernate-mapping tag to both true and false

  3. Add mapping assembly tag in hibernate.cfg.xml, also checked the namespace and assembly name.

  4. Adding a mapping resource tag in hibernate.cfg.xml file which gives an error of ambiguous mapping tag.

What more can I try? The error arises just before session.save() line, and the query retrieving count of rows in the table above session.save works fine.

Additionally following is the full error message:

NHibernate.MappingException was unhandled
  HResult=-2146232832
  Message=No persister for: NhibernateORM.Layout
  Source=NHibernate
  StackTrace:
       at NHibernate.Impl.SessionFactoryImpl.GetEntityPersister(String entityName)
       at NHibernate.Impl.SessionImpl.GetEntityPersister(String entityName, Object obj)
       at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
       at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
       at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
       at NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
       at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
       at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
       at NHibernate.Impl.SessionImpl.Save(Object obj)
       at NhibernateORM.Program.Main(String[] args) in d:\codebase\NhibernateORM\NhibernateORM\Program.cs:line 57
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
1

There are 1 answers

2
Radim Köhler On

I'd say, because all that information, we should have a culprit. There are so many issues (well problems in fact) with the mapping and C# code, that we for sure know:

the Mapping.hbm.xml is not correctly configured, not used, not visible for NHibernate

In case, that this file as is would be available to NHibernate session factory, we would get this Exception

System.TypeInitializationException: The type initializer for 'Instance' threw an exception. ---> NHibernate.MappingException: Could not compile the mapping document: NhibernateORM.Mapping.hbm.xml ---> NHibernate.MappingException: persistent class Layout, NhibernateORM not found ---> System.TypeLoadException: Could not load type 'Layout' from assembly 'NhibernateORM...

Which could be fixed by adding namespace attribute to mapping namespace="NhibernateORM"

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
  assembly="NhibernateORM"
  namespace="NhibernateORM"
  auto-import="true">
  <class name="Layout" table="mytable">
    <id name="Id" column="ID" type="int" generator="assigned" />
    <property name="Name"        column="name"        type="String"/>
    <property name="xCoordinate" column="xCoordinate" type="double" />
    <property name="yCoordinate" column="yCoordinate" type="double" />
  </class>
</hibernate-mapping>

Once that would be fixed, we would later get this exception

NHibernate.InvalidProxyTypeException: The following types may not be used as proxies: NhibernateORM.Layout: method get_Id should be 'public/protected virtual' or 'protected internal virtual'...

which could be fixed by making all the Entity stuff virtual:

namespace NhibernateORM
{
    public class Layout
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual double xCoordinate { get; set; }
        public virtual double yCoordinate { get; set; }

So, for sure, we know - the issue is

  • wrong configuration in the hibernate.cfg.xml
  • wrong configuration of the Mapping.hbm.xml properties

This should be part of the hibernate.cfg.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
      ...
      <mapping assembly="NhibernateORM"/>

the hibernate.cfg.xml must have properties:

  • Build Action === Content
  • Copy to Output Directory === Copy always

the Mapping.hbm.xml must have properties:

  • Build Action === Embedded Resource
  • Copy to Output Directory === Do not copy