NHibernate ClassMappings = 0 - nhibernate

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.

Related

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.

How to Define Prototype Interceptors with DefaultAdvisorAutoProxyCreator in Spring.NET

I am new to Spring.NET and am just playing around trying different things out. As part of my testing, I created a simple object:
public interface ICommand {
void Execute(object context);
}
with one implementation:
public class ServiceCommand : ICommand {
public ServiceCommand() {
Console.WriteLine("########## {0} ##########", GetType().Name);
}
public void Execute(object context) {
Console.WriteLine("Service implementation: {0}.{1}", GetType().Name, MethodBase.GetCurrentMethod().Name);
}
}
Finally, I've a simple before advice as follows:
public class ConsoleLoggingBeforeAdvice : IMethodBeforeAdvice {
public ConsoleLoggingBeforeAdvice() {
Console.WriteLine("########## {0} ##########", GetType().Name);
}
public void Before(MethodInfo method, object[] args, object target) {
Console.WriteLine("Intercepted call to this method: {0}", method.Name);
Console.WriteLine(" The target is : {0}", target);
Console.WriteLine(" The arguments are : ");
if (args != null) {
foreach (object arg in args) {
Console.WriteLine("\t: {0}", arg);
}
}
}
}
As you can see, much of this stuff is from the Spring.NET quick start samples.
So, I configured the ServiceCommand to be wrapped in a ConsoleLoggingBeforeAdvice via ProxyFactoryObject and marked both the objects as prototype (see config below). This works as expected: each time we request a ServiceCommand, a new instance of both the object and associated interceptor is created:
<?xml version="1.0" encoding="utf-8"?>
<objects xmlns="http://www.springframework.net">
<object id="ConsoleLoggingBeforeAdvice" type="Spring.Aop.Support.DefaultPointcutAdvisor" singleton="false">
<property name="Advice">
<object type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>
</property>
</object>
<object id="ServiceCommandTarget" type="Spring.Examples.AopQuickStart.ServiceCommand" singleton="false"/>
<object id="ServiceCommand" type ="Spring.Aop.Framework.ProxyFactoryObject">
<property name="IsSingleton" value="false"/>
<property name="TargetName" value="ServiceCommandTarget"/>
<property name="InterceptorNames">
<list>
<value>ConsoleLoggingBeforeAdvice</value>
</list>
</property>
</object>
</objects>
However, when I try to achieve the same results via DefaultAdvisorAutoProxyCreator, everything works except that the interceptor is always created as Singleton (even though it's configured as singleton="false"). The config is as follows:
<?xml version="1.0" encoding="utf-8"?>
<objects xmlns="http://www.springframework.net">
<object id="ConsoleLoggingBeforeAdvice" type="Spring.Aop.Support.DefaultPointcutAdvisor" singleton="false">
<property name="Advice">
<object type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>
</property>
</object>
<object id="ServiceCommand" type="Spring.Examples.AopQuickStart.ServiceCommand" singleton="false"/>
<object type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator"/>
</objects>
Now, how can I ensure that both the object and associated interceptor are treated as prototypes by DefaultAdvisorAutoProxyCreator?
OK, I've figured out that setting InterceptorNames on DefaultAdvisorAutoProxyCreator will correctly instantiate interceptors as prototypes (if they're configured so). But this somehow feels incorrect as the DefaultAdvisorAutoProxyCreator should be able to pick interceptors from advisors and honor their configuration settings.
I am still not 100% clear on how to create prototype interceptors under different scenrarios. For example, all my attempts to create thread-scoped interceptors while using DefaultAdvisorAutoProxyCreator have failed.
Anyways, here's the xml config that works for me:
<?xml version="1.0" encoding="utf-8"?>
<objects xmlns="http://www.springframework.net" default-autowire="constructor">
<object id="ConsoleLoggingBeforeAdvice" type="Spring.Aop.Support.DefaultPointcutAdvisor" singleton="false">
<property name="Advice">
<object type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>
</property>
</object>
<object id="ServiceCommand" type="Spring.Examples.AopQuickStart.ServiceCommand" singleton="false"/>
<object type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator">
<property name="InterceptorNames" value="ConsoleLoggingBeforeAdvice"/>
</object>
</objects>
I am totally confused with the idea of creating prototype interceptors. Are interceptors supposed to be or recommended to be prototypes at all or should they always be singletons?

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.

Configuring Fluent NHibernate from NHibernate config section

I'm trying to use Fluent NHibernate in my solution by configuring it with the following NHibernate xml configuration section
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="mitre">
<property name="dialect">NHibernate.Dialect.Oracle9iDialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.OracleDataClientDriver</property>
<property name="connection.connection_string">Data Source=YOUR_DB_SERVER;Database=Northwind;User ID=YOUR_USERNAME;Password=YOUR_PASSWORD;</property>
<property name="connection.isolation">ReadCommitted</property>
<property name="default_schema">TRATE</property>
<!-- HBM Mapping Files -->
<mapping assembly="Markel.Mint.Mitre.Data" />
</session-factory>
</hibernate-configuration>
In my code file, to instantiate ISession:
NH_Cfg.Configuration cfg = new NH_Cfg.Configuration();
cfg.Configure();
Fluently.Configure(cfg).Mappings(m => m.FluentMappings = ????)
My question is that if I have already specified the assembly in the NHibernate config section, do I need to explicitly set FluentMappings? If so, then is it possible to retrieve this data from NHibernate config programmatically?
Thanks
Oz
The mapping assembly in hibernate.cfg.xml is searched for embedded *.hbm.xml files. NHibernate does not know anything about fluent mappings (e.g. ClassMap) as those are introduced by Fluent NHibernate. So you need:
Fluently.Configure(cfg).Mappings(m => m.FluentMappings.AddFromAssemblyOf<SomeDomainType>();
in order to configure NHibernate using your ClassMap mappings.
Thanks for the quick response, James.
Could I do the following then?
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="mitre">
<property name="dialect">NHibernate.Dialect.Oracle9iDialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.OracleDataClientDriver</property>
<property name="connection.connection_string">Data Source=YOUR_DB_SERVER;Database=Northwind;User ID=YOUR_USERNAME;Password=YOUR_PASSWORD;</property>
<property name="connection.isolation">ReadCommitted</property>
<property name="default_schema">TRATE</property>
<property name="fluent.nhibernate.fluentmapping">Markel.Mint.Mitre.Core.Domain</property>
</session-factory>
</hibernate-configuration>
Then my code could refer to the property thus:
NH_Cfg.Configuration cfg = new NH_Cfg.Configuration(); cfg.Configure();
Fluently.Configure(cfg).Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.Load(cfg.Properties["fluent.nhibernate.fluentmapping"])));

How to configure RetryAdvice and ExceptionTranslation for Deadlocks using NHibernate and Spring

i am using Spring.net 1.2 with NHibernate 2.0.1.
Within my project i'am facing some Deadlock issues and besides the database tweaks to minimize the occurence i would like to implement Springs RetryAdvice to handle this.
I can't find any working example how to configure a this. The reference seems to be clear about how to use it but somehow i can't get it working.
<!--Used to translate NHibernate exception to Spring.DataAccessExceptions-->
<object type="Spring.Dao.Attributes.PersistenceExceptionTranslationPostProcessor, Spring.Data"/>
<!--ExceptionHandler performing Retry on Deadlocks-->
<object name="ExceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
<property name="retryExpression" value="on exception name DeadLockLoserException retry 3x rate (1*#n + 0.5)"/>
</object>
I have added the [Repository] attribute to my DAOs to get ExceptionTranslation enabled and tried to add the RetryAdvice to the TransactionProxyFactoryObject i am using but it won't work. I don't understand where to put this Advice. Do i have to declare a PointCut to add it or how could i get it to work as expected.
Thx in advance - any help appreciated.
After 1 and a half month of waiting for someone solving my problem i finally found time to elaborate the solution for this by myself. In fact it wasn't that difficult i thought it was. Maybe thats why i wasn't able to find any good example.
So here we go: The following test will show the usage:
Configuration: (SessionFactory and TransactionManager etc. omitted for brevity)
<!-- Retries the Tx after DeadlockExceptions -->
<object name="ExceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
<property name="retryExpression" value="on exception name DeadlockLoserDataAccessException retry 3x delay 1s"/>
</object>
<!--A Transaction-Configuration for our DAO-MOCK-->
<object id="TxProxyConfigurationTemplate" abstract="true" type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
<property name="PlatformTransactionManager" ref="HibernateTransactionManager"/>
<property name="TransactionAttributes">
<name-values>
<add key="ThrowDeadLock*" value="PROPAGATION_REQUIRED"/>
</name-values>
</property>
</object>
<object id="MockDaoTxPFO" parent="TxProxyConfigurationTemplate">
<property name="Target" ref="MockDao"/>
</object>
<!--The ProxyFactoryObject based on the DAO-Mock interface-->
<object id="MockDao" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop" >
<property name="proxyInterfaces" value="RetryAdvice.IDaoMock"/>
<property name="target" ref="MockDaoImpl"/>
<property name="interceptorNames">
<list>
<value>ExceptionHandlingAdvice</value>
</list>
</property>
</object>
<!--Mocked DAO Implementation -->
<object id="MockDaoImpl" type="RetryAdvice.DaoMock, RetryAdvice">
<constructor-arg name="maxExceptionCount" value="2" />
</object>
Mocked Dao: This DAO will throw DeadLockLooserExceptions twice and then pass.
public interface IDaoMock
{
void ThrowDeadLock();
int MethodCallCount { get; }
}
[Repository]
public class DaoMock : IDaoMock
{
private int maxExceptionCount;
public int MethodCallCount { get; private set; }
public DaoMock(int maxExceptionCount)
{
this.maxExceptionCount = maxExceptionCount;
}
public void ThrowDeadLock()
{
MethodCallCount++;
if (MethodCallCount <= maxExceptionCount)
{
throw new DeadlockLoserDataAccessException("FAKE", new HibernateException("This is a fake Exception.", null));
}
}
The Test:
[Test]
public void RetryAdviceTest()
{
IDaoMock mockDao = (IDaoMock)this.appContext.GetObject("MockDaoTxPFO");
mockDao.ThrowDeadLock();
Assert.That(mockDao.MethodCallCount, Is.EqualTo(3));
}
Any hints or remarks appreciated.