NHibernateHelper - many tables - nhibernate

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.

Related

How can I Run hibernate application with datasource in Intellij IDEA

Hibernate.cfg.xml
<property name="connection.datasource">java:/comp/env/jdbc/MyStatus-process</property>
web.xml
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/MyStatus-process</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
HibernateUtil class
private static SessionFactory buildSessionFactory() {
try {
Configuration configuration = new Configuration().configure("hibernate.cfg.xml"); //configuration settings from hibernate.cfg.xml
StandardServiceRegistryBuilder serviceRegistryBuilder = new StandardServiceRegistryBuilder();
serviceRegistryBuilder.applySettings(configuration.getProperties());
ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
return configuration.buildSessionFactory(serviceRegistry);
}
catch (Throwable ex) {
log.error("--- Exception while creating the initial session factory creation ---", ex);
throw new ExceptionInInitializerError(ex);
}
}
I was not able to run with above configuration. Can any one give some ideas on it.
I was able to run with below configuration:
Working Hibernate Configuration:
<property name="hibernate.connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:jtds:sqlserver://localhost:1433/DB_INSTANCE_NAME;tds=8.0;lastupdatecount=true</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password">sa1234</property>
<property name="hibernate.dialect">org.hibernate.dialect.SQLServer2012Dialect</property>

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.

Spring AfterReturningAdvice firing before transaction commits

I seem to be having a weird problem. In our services layer, we are using WCF with nHibernate and Spring.NET 1.3.0.20349. I don't have the option to upgrade spring to the next version.
I have save methods on a service that has AfterReturningAdvices which are required to make another service call that calls into the Db and uses the ID of the saved object. The problem is that the interceptor is firing before the transaction commits which is causing the next service call to return empty objects
After some reading, my understanding of Springs Interceptors are :
The pre-interceptors beforeadvice methods run
Spring starts the transaction
The post-interceptors beforeadvice methods run
The main service method runs
The post-interceptors afterreturning advice methods run
Spring commits the transaction
The pre-interceptors afterreturning advice methods run
My web.config has the following:
<object id="InsertPointcut" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">
<property name="advice">
<ref local="afterAddInterceptor"/>
</property>
<property name="MappedNames">
<list>
<value>AddToEvent</value>
</list>
</property>
</object>
<object id="UpdatePointcut" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">
<property name="advice">
<ref local="afterUpdateInterceptor"/>
</property>
<property name="MappedNames">
<list>
<value>Update</value>
</list>
</property>
</object>
<object id="ServiceProxy" type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
<property name="PlatformTransactionManager" ref="transactionManager"/>
<property name="TransactionAttributeSource" ref="attributeTransactionAttributeSource"/>
<property name="target">
<object id="Service" type="Service, Service" init-method="init">
<constructor-arg ref="sessionFactory" />
<property name="EventRepository" ref="eventRepository" />
</object>
</property>
<property name="preInterceptors">
<list>
<ref local="throwsAdvice"/>
<ref local="InsertPointcut"/>
<ref local="UpdatePointcut"/>
</list>
</property>
</object>
Can anyone help?
[Update]
In order to avoid making code changes to my services, I implemented the ITransactionSynchronization interface on my advice and registered it. That way, in the AfterCompletion method, I can do my work after spring & nHibernate has committed. I'm not sure if there is a better way to handle this but it seems to work.
public class AfterUpdateInterceptor : IAfterReturningAdvice, ITransactionSynchronization
{
private int id;
[Transaction]
public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target)
{
TransactionSynchronizationManager.RegisterSynchronization(this);
if (args == null || args.Length == 0)
{
return;
}
id = PropertyHelper.GetIdPropertyValue<IUpdateContract>(args);
}
public void Suspend()
{
}
public void Resume()
{
}
public void BeforeCommit(bool readOnly)
{
}
public void AfterCommit()
{
}
public void BeforeCompletion()
{
}
public void AfterCompletion(TransactionSynchronizationStatus status)
{
if (status != TransactionSynchronizationStatus.Committed) return;//.com msg not sent.
if (id > 0)
{
XmlSender.SendXmlUpdate(MessageType.Update, id);
}
id = 0;
}
}
From looking at the source of the TransactionProxyFactoryObject's AfterPropertySet Method, I think that is in fact the order of the applied advices. So you should have a AfterReturningAdvice configured in your pre-interceptors.
If this isn't called, it might be a bug and I would suggest to ask in the spring.net forums.
Another way to get called when an transaction is comitted is the ITransactionSynchronization Interface which can be registered with the TransactionSynchronizationManager.

NHibernate ClassMappings = 0

I am trying to user NHibernate / FluentNHibernate to create a table in my database. I seem to have figured it out for the most part but when I run the test the table isn't created. I see in the Configuration object that the ClassMappings is a big fat zero even thought I have user FluentNHibernate to configure them from an assembly. I somewhat understand this but I am missing some connection somewhere... Here is the code snippets, maybe someone can see what I forogt?
Here is my dataconfig class.
public static FluentConfiguration GetFluentConfiguration()
{
string hibernateCfgFile = #"C:\Users\kenn\Documents\Visual Studio 2008\Projects\NHibernateTestTwo\Infrastructure\hibernate.cfg.xml";
return Fluently.Configure(new Configuration().Configure(#hibernateCfgFile))
.Mappings(cfg => cfg.FluentMappings.AddFromAssembly(typeof(AddressMap).Assembly));
}
Here is the test class.
[Test, Explicit]
public void SetupDatabase()
{
FluentConfiguration conf = DataConfig.GetFluentConfiguration();
conf.ExposeConfiguration(BuildSchema).BuildSessionFactory();
}
private static void BuildSchema(Configuration conf)
{
new SchemaExport(conf).SetOutputFile("drop.sql").Drop(false, true);
new SchemaExport(conf).SetOutputFile("create.sql").Create(false, true);
}
Here is the mappings
public AddressMap()
{
Table("Address");
DynamicUpdate();
Id(a => a.Id).GeneratedBy.GuidComb();
Map(a => a.AddressOne).Not.Nullable().Length(100);
Map(a => a.AddressTwo).Length(100);
Map(a => a.City).Not.Nullable().Length(100);
Map(a => a.state).Not.Nullable().Length(100);
Map(a => a.zip).Not.Nullable().Length(50);
Map(a => a.Primary).Not.Nullable();
}
The hibernate.cfg.xml file
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
Data Source=MYPC;Initial Catalog=NHibernateSample;Integrated Security=True;
</property>
<property name="show_sql">true</property>
<property name="dialect">
NHibernate.Dialect.MsSql2005Dialect
</property>
<property name="adonet.batch_size">100</property>
<!--<property name="proxyfactory.factory_class">
NHibernate.ByteCode.LinFu.ProxyFactoryFactory,
NHibernate.ByteCode.LinFu
</property>-->
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.Castle.ProxyFactoryFactory,
NHibernate.ByteCode.Castle
</property>
</session-factory>
I am just not sure what is missing there... It clearly is talking to the DB cause if I change the name of the database to something that doesn't exist it trows an exception, I am stuck - I have gone round and round on this and just haven't figured it out yet so any help would be greatly appreciated.
Thanks!
See my comment... Don't forget to make your map classes public or FluentNHibernate won't see them.

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.