NHibernate MappingException. No Persister - nhibernate

I'm trying to get NHibernate to work. I've got this class:
mm.k.Domain.Kampagne
(namespace/assembly is mm.k.Domain)
In another Visual Studio project (Assembly mm.k.Infrastructure) I got my Mapping files (in a Mappings directory), my hibernate.cfg.xml and some repositories.
Heres my mapping file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="mm.k.Domain"
namespace="mm.k.Domain">
<class name="Kampagne" table="Kampagner">
<id name="Id">
<generator class="identity" />
</id>
<property name="Navn" not-null="true" />
<property name="Logo" />
</class>
</hibernate-mapping>
When I'm configuring my session, I do this:
_configuration.AddAssembly(typeof(mm.k.Domain.Kampagne).Assembly);
And thats what doesn't work!
When calling:
var test = session.Get<Kampagne>(kampagneId);
I get the following error:
"No persister for: mm.k.Domain.Kampagne"
Like it doesn't register the embedded mapping fild. Note that I have the build action on the mapping file set to Embedded Resource.
If I change the above line to:
_configuration.AddFile(#"fullpath\mm.k.Infrastructure\Mappings\Kampagne.hbm.xml");
Everything works perfectly fine!
Any ideas? Thanks in advance.

In case someone will have this issue with Hibernate.NET as I did.
Make sure you selected in Properties Window for your file Build Action as "Embedded Resource".

Not sure what your nhibernate.cfg.xml file looks like, but I generally have an item like this
<mapping assembly="mm.K.Infrastructure"/>
based on your information you've given. NHibernate uses this to load the mapping files from this specific assembly.
This should give you the mapping you need.

I was Getting the problem. But suddenly observed that the mapping file was not embedded.
Goto the .hbm.xml file. Click properties. Then advanced -> Select "Embedded Resource"

Whenever you use hbm.xml file you will set your configuration class like this:
Configuration cfg = new Configuration();
cfg.Configure();
// Add class mappings to configuration object
cfg.AddAssembly(Assembly.GetCallingAssembly());
ISessionFactory sessionFactory = cfg.BuildSessionFactory();
Whenever you use Nhibernate.Mapping.Attributes like classe you will have to use:
For example you have use Mapping.attributes in Product Class
Configuration cfg = new Configuration();
cfg.Configure();
// Add class mappings attributes to configuration object
cfg.AddInputStream(HbmSerializer.Default.Serialize(typeof(Model.Product);
ISessionFactory sessionFactory = cfg.BuildSessionFactory();

Related

Nhibernate hbm to Fluent

I have a requirement to write the mapping using Nhibernate fluent.
I have the following in hbm
<class name="XYZ" table="Some_Table">
<composite-id>
<key-many-to-one name="A" column="A_ID"/>
<key-property name="Term" type="Some_Assembly">
<column name="YEAR"/>
<column name="MONTH"/>
</key-property>
</composite-id>
<property name="P" column="P"/>
</class>
and I would need to rewrite this in fluent. the main reason is that we are moving away from hbm files to fluent.
so far I have the following
public class XYZMap: ClassMap<XYZ>
{
public XYZMap()
{
Table("Some_Table");
CompositeId()
.KeyProperty(x=> x.Term, set =>
{
set.ColumnName("Year");
set.ColumnName("Month");
set.Type(typeof(Some_Assembly));
})
.KeyProperty(x=> x.A, set =>
{
set.ColumnName("A");
set.Type(typeof (Other_Assembly));
});
Map(x=> x.P, "P");
}
}
But I am getting the following error
X.Y.TestZ.PostCreate:
SetUp : Autofac.Core.DependencyResolutionException : An exception was thrown while executing a resolve operation. See the InnerException for details.
----> FluentNHibernate.Cfg.FluentConfigurationException : An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
----> NHibernate.MappingException : Could not compile the mapping document: (XmlDocument)
----> NHibernate.MappingException : Could not determine type for: Other_Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, for columns: NHibernate.Mapping.Column(A_ID)
I think I am unable to map many-to-one when I am trying to configure using fluent.
So can someone please help.
You should be using KeyReference instead for column A.
.KeyReference(x => x.A, "A");

NHibernateHelper - many tables

I am new in NHibernate, I have based on tutorial: http://nhibernate.info/doc/tutorials/first-nh-app/your-first-nhibernate-based-application.html . So I have NHibernateHelper:
public class NHibernateHelper {
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof (Product).Assembly);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
} }
But I have also entity Category and User? Do I need each entity add to configuration using code AddAssembly?? Because when I have added code:
configuration.AddAssembly(typeof (Product).Assembly);
configuration.AddAssembly(typeof(Category).Assembly);
I have error:
Could not compile the mapping document: MvcApplication1.Mappings.Product.hbm.xml
First check whether you have set the "Build Action" of all the mapping files (*.hbm.xml) to "Embedded Resource". This is VERY important.
Then you only need to add a call to AddAssembly once as NHibernate is clever enough to scan through the assembly to sniff out all your entities that map to all your embedded hbm.xml files..
e.g. You only need to supply the assembly once that contains all your entities:-
_configuration.AddAssembly(typeof (Product).Assembly);
NHibernate will now find Category (and all others) automatically as long as they are in the same assembly as Product. HTH
you can alternatively add the mapping tag into the web.config, instead of adding it in code on the SessionFactory initialization. Then, your code will look like this:
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
_sessionFactory = configuration.BuildSessionFactory();
}
And in the web config you will have to indicate the assembly where all of your mappings are, like this:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="dialect">
NHibernate.Dialect.MsSql2005Dialect
</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
-- YOUR STRING CONNECTION --
</property>
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle
</property>
<mapping assembly="You.Assembly.Namespace" />
</session-factory>
Being the important configuration tag "mapping assembly="Your.Assembly.Namespace". As the other contributor mentioned before, it is very important that you mark each of the hbm.xml file as embedded resource, otherwise it will be as you never created it. By doing this, you just need to create all of the mappings inside of this assembly (project) and those will be automatically read when NH configures.

Why is my WCF Data Services method not appearing in the OData collections list?

When I view the root of my WCF Data Services service (http://localhost/MyService.svc/) in a browser I see this:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<service xml:base="http://localhost/MyService.svc/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">
<workspace>
<atom:title>Default</atom:title>
</workspace>
</service>
I would expect to see a list of collections.
When I go to the $metadata URL I see this:
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="1.0">
<Schema Namespace="MyApp" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2007/05/edm">
<ComplexType Name="Package">
<Property Name="Id" Type="Edm.String" Nullable="true" />
</ComplexType>
</Schema>
<Schema Namespace="MyApp" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2007/05/edm">
<EntityContainer Name="PackageService" m:IsDefaultEntityContainer="true">
<FunctionImport Name="GetQueryablePackages" ReturnType="Collection(MyApp.Package)" m:HttpMethod="GET" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Why might my GetQueryablePackages collection not be appearing?
I'm using these access settings:
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
Service operations (the function import in the EDM) is not exposed in the service document. Only entity sets are exposed there.
If you want your data to be exposed in the service document make an entity set out of it. Depending on the provider model this differs. Typically it means exposing a property of type IQueryable on your context class. Note that T has to be an entity type (must have a key).
Can you share the context definition where you have defined the IQueryable <> properties. There are 2 things that come to my mind: First the properties must be of type IQueryable<> or some type that derives from it. Second, the element type refered by the IQueryable<> must be an entity type i.e. they must have key properties declared in them.
Hope this helps.
Thanks
Pratik
Or you can create an extension method like this:
public static class TestEntitiesExtensions
{
public static IEnumerable<Package> GetQueryablePackages(this TestEntities context)
{
var uri = new Uri(context.BaseUri, "GetQueryablePackages");
return context.Execute<Package>(uri);
}
}

How to write custom nHibernate dialect?

I am using NHibernate with a legacy rdbms rule engine. I am using GenericDialect but some of the sql generated are not working. If I need to write custom Dialect for this rule engine how do start?
This is an example dialect:
using System;
using System.Collections.Generic;
using System.Web;
///
/// This class ensures that the tables created in our db are handling unicode properly.
///
public class NHibernateMySQL5InnoDBDialect : NHibernate.Dialect.MySQL5Dialect
{
public override String TableTypeString { get { return " ENGINE=InnoDB DEFAULT CHARSET=utf8"; } }
}
The assembly it's in has a reference to NHibernate.dll
hibernate.cfg.dll (note that I don't have 'connection.connection_string' property set here, this is my setup specific and usually you would have connection string here) :
<?xml version="1.0" encoding="utf-8"?>
<!-- This is the ByteFX.Data.dll provider for MySql -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="NHibernate.Test">
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
<property name="dialect">NHibernateMySQL5InnoDBDialect, Assembly1</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
</session-factory>
</hibernate-configuration>
In some setups the dialect line would be
<property name="dialect">Assembly1.NHibernateMySQL5InnoDBDialect, Assembly1</property>
And the code creating an ISessionFactory:
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.Configure();
cfg.Properties["connection.connection_string"] = ConnectionStringForDatabase();
cfg.AddDirectory(PathToMappingsIfYouUseNonStandardDirectory);//not needed if using embedded resources
return cfg.BuildSessionFactory();
I would start by grabbing the nhibernate source, the 2.1.x branch is here. The existing Dialects are all under src/NHibernate/Dialect.
Copy one and start hacking. The base class Dialect has many extension points.

How to properly configure NHibernate event listeners

I'm trying to use an event listener for the first time. All samples I've seen show how easy it is to configure, but for some reason I'm having trouble - it doesn't seem to be called. I suspect I'm missing something obvious.
I've tried this:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory name="TerraCognita.LoanExpress">
<!-- other stuff... -->
<listener type="delete" class="Test.TestDeleteListener, MyDllName" />
</session-factory>
</hibernate-configuration>
as well as:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory name="TerraCognita.LoanExpress">
<!-- other stuff... -->
<event type="delete">
<listener class="Test.TestDeleteListener, MyDllName" />
</event>
</session-factory>
</hibernate-configuration>
When configuration is loaded and the session factory is built:
var cfg = new NHibernate.Cfg.Configuration();
cfg.AddAssembly("MyDllName");
sessionFactory = cfg.BuildSessionFactory();
After instantiation, cfg.EventListeners.DeleteEventListeners has a single entry, of type DefaultDeleteEventListener (as I'd expect). However, after cfg.AddAssembly is called, this is still the case - but given the configuration, I would expect that the DeleteEventListener should actually be of type TestDeleteListener.
In my unit test, the only way I can get my event listener working is by manually adding it to the session info:
var sess = GetSession();
sess.GetSessionImplementation().Listeners.DeleteEventListeners =
new NHibernate.Event.IDeleteEventListener[] { new TestDeleteListener() };
I know this shouldn't be required, and I should be able to configure it properly. Can anyone shine a light on what I'm doing wrong here?
Your configuration is ok, it's just that you overlooked to call cfg.Configure(). Change your initialization code to this and your fine:
var cfg = new NHibernate.Cfg.Configuration();
cfg.Configure();
cfg.AddAssembly("MyDllName");
sessionFactory = cfg.BuildSessionFactory();