NHibernate - Why is connection needed to build factory if connection can be passed to session constructor? - nhibernate

I'm new to NHibernate and am attempting to use it to connect to DB2. After trial and error and research, and more trial and error and research, I've finally come down to an error to which I cannot find an answer.
The error message reads: "The user must provide an ADO.NET connection - NHibernate is not creating it."
This error is not very helpful. Does this mean that I need to 1) put a connection string in my config file or 2) do I need to pass the connection into the factory? If 1 is true, is this mandatory? If it is then why are we given the ability to pass the connection object into the session which is what I desire to do?
If 2) is true, how do I pass in a connection object into the factory?
Thank you in advance. Below are my code snippets which may be helpful:
<?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.DB2400Dialect</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
</session-factory>
</hibernate-configuration>
</configuration>
try
{
Configuration cfg = new Configuration();
cfg.AddInputStream(NHibernate.Mapping.Attributes.HbmSerializer.Default.Serialize(persistentClass));
SessionFactory = cfg.Configure().BuildSessionFactory(); //HERE I GET THE EXCEPTION
}
catch (Exception ex)
{
throw new Exception("NHibernate initialization failed", ex);
}

You need the session factory for configuration like connections, what kind of mapping you use, what kind of caches you use, what kind of sql dialect, etc. Not just the connection, so passing a connection as constructor argument probably will give you another unhelpful exception. You have to setup the connection in your configuration.

If you look at the documentation you should be able to see how to create the session factory programaticaly. Alternatively you could use fluentNhibernate to avoid that configuration file.

Related

org.apache.tomcat.dbcp.dbcp.BasicDataSource cannot be cast to net.sourceforge.jtds.jdbcx.JtdsDataSource

Trying to connect to a (local) SQL database using jTDS JDBC drivers.
JAVA CODE
private JtdsDataSource dataSource = null;
public Connection getConnection() throws SQLException, NamingException {
...
Context initContext = new InitialContext();
dataSource = (JtdsDataSource) initContext.lookup("java:comp/env/jdbc/postcodes");
conn = dataSource.getConnection();
...
}
CONTEXT.XML
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/postcodes"
auth="Container"
type="javax.sql.DataSource"
username="user"
password="pass"
driverClassName="net.sourceforge.jtds.jdbcx.JtdsDataSource"
url="jdbc:jtds:sqlserver://localhost:1433/AUSPostcodes"
validationQuery="select 1"
maxActive="10"
maxIdle="4"/>
</Context>
When I run this on tomcat, get the following error....
java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.BasicDataSource cannot be cast to net.sourceforge.jtds.jdbcx.JtdsDataSource
Would appreciate some help with this.
Thanks in advance.
Tomcat doesn't give you access to a JtdsDataSource directly. It only uses that datasource to populate its internal DBCP datasource. When you use JNDI to ask for a datasource, you get the DBCP datasource.
BTW: There is (usually) no reason why you would cast to any other interface than javax.sql.DataSource. The solution therefor is to cast to that interface (javax.sql.DataSource).

MVC 5 NHibernate Autofac, not able to see database data

I'm building an MVC5 web app connecting to a MS SQL 2008 database, so that the users can search and make changes to data stored there. I've looked at a bunch of autofac tutorials and examples, but can't seem to make any of them work.
I'm assuming my autofac configuration is the problem, because when I run the app it says my model is null. Which I think means the autofac is not connecting to the datbase.
So, in my global.asax.cs file I have the following:
protected void Application_Start()
{
#region Autofac
// Register Controllers
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly); //all controllers in assembly at once ?
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterFilterProvider();
// Set the Dependency Resolver
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Register Model Binders
builder.RegisterModelBinders(typeof(MvcApplication).Assembly); //all binders in assembly at once ?
builder.RegisterModelBinderProvider();
// Register Modules
builder.RegisterModule<PersistenceModule>();
#endregion
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
I have a hibernate.cfg.xml file as
<?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="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Data Source=DEVSRV\SQLSERVER;Initial Catalog=tipdemo;Persist Security Info=True;User ID=admin;Password=***********</property>
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
<!--<mapping assembly="NHibernateTest"/> -->
</session-factory>
</hibernate-configuration>
</configuration>
And my PersistenceModule class is:
public class PersistenceModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
if (builder == null)
throw new ArgumentException("builder", "builder is null");
base.Load(builder);
}
private ISessionFactory ConfigureDB()
{
Configuration cfg = new Configuration().Configure(System.Web.HttpContext.Current.Server.MapPath("~/Config/hibernate.cfg.xml"));
cfg.AddAssembly(typeof(Domain.General.Project).Assembly);
return cfg.BuildSessionFactory();
}
}
You can't register things in the container after it's built.
On line 11 in the sample for Application_Start you're building the container, but then after you set the DependencyResolver you're registering more stuff with the ContainerBuilder. You can't do that - you have to register everything first, then build the container as the last thing you do.
That's why it's never entering your PersistenceModule - you've already built the container, so it's not actually getting registered.
If, for some reason, you need to add registrations to an already-built container, you need to create an all new ContainerBuilder and call builder.Update(container). However, I strongly recommend you just reorder things so the container is built last rather than go the Update route if possible.

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.

NHibernate MappingException. No Persister

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();

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();