Fluent NHibernate caching with automapping - nhibernate

I'm trying to understand how to configure Fluent NHibernate to enable 2nd-level caching for queries, entities, etc... And at the same time use automapping. There is very little information online on how to do that. Sure it can be done when mapping the classes one by one... But how about automapping?
Here is my configuration code so far:
AutoPersistenceModel model = AutoMap.AssemblyOf<Seminar>()
.Where(t => t.Namespace == "[MY NAMESPACE]")
.Conventions.Add(DefaultCascade.All());
Configuration config = Fluently.Configure()
.Database
(
MsSqlConfiguration.MsSql2005
.ConnectionString(#"[MY CONNECTION STRING]")
)
.Mappings(m => m.AutoMappings.Add(model))
.BuildConfiguration();
_sessionFactory = config.BuildSessionFactory();
Thanks!

Assuming you've already downloaded a 2nd-level cache provider from the NHibernate Contribution project, you should be able to use the following to initialize the cache within your automappings setup.
Configuration config = Fluently.Configure()
.Database
(
MsSqlConfiguration.MsSql2005
.ConnectionString(#"[MY CONNECTION STRING]")
.Cache(c => c.UseQueryCache().ProviderClass<YourCacheProviderOfChoice>())
)
.Mappings(m => m.AutoMappings.Add(model))
.BuildConfiguration();
Selecting the queries you want to cache is simply a matter of calling SetCacheable(true) on your Criteria instance.
var query = session.CreateQuery("from Blog b where b.Author = :author")
.SetString("author", "Gabriel")
.SetCacheable(true);
var list = query.List<Blog>();
This is an epic blog post on NHibernate's first and second level caches, good reference material.

I've been struggling with this for a while and was surprised how little information is out there. This question is the best I could find and even here the accepted answer doesn't say how to enable entity caching. Here's what I've found out.
To enable second level cache:
Fluently.Configure()
.Database(/* your DB config */)
.Cache(c => c.UseSecondLevelCache().ProviderClass<CacheProviderClass>())
You can use both this and query cache:
Fluently.Configure()
.Database(/* your DB config */)
.Cache(c => c.UseSecondLevelCache()
.UseQueryCache()
.ProviderClass<CacheProviderClass>())
To enable per-entity caching:
.Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<Entity>()
.Conventions.Add(ConventionBuilder.Class.Always(c => c.Cache.ReadWrite()))
)
)
Of course, you can use ReadOnly() or NonStrictReadWrite() if you wish.

Related

Cache configurations of FluentNHibernate?

I'm using FluentNhibernate version 2.0.3.0 and I'm trying to configure the cache of it to use with queries, I'm using HQL. I want to one opinion if I did all configurations alright, and I want to know how could I see if cache was activate ?
Connection
FluentConfiguration _config = Fluently.Configure()
.Database(
MySQLConfiguration.Standard.ConnectionString(
x => x.Server(HOST)
.Username(USER)
.Password(PASSWORD)
.Database(DB)))
.Cache(c => c.ProviderClass(typeof(NHibernate.Cache.HashtableCacheProvider).AssemblyQualifiedName)
.UseQueryCache())
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UsuarioMap>())
.ExposeConfiguration(cfg => new SchemaUpdate(cfg)
.Execute(false, true));
Mapping
public class UsuarioMap : ClassMap<Usuario> {
public UsuarioMap() {
Table("USUARIOS");
Cache.ReadWrite();
Id(u => u.id).GeneratedBy.Native();
Map(u => u.nome).Not.Nullable().Length(50);
Map(u => u.email).Unique().Not.Nullable().Length(255);
Map(u => u.senha).Not.Nullable();
Map(u => u.status).CustomType<int>();
Map(u => u.dtCadastro).CustomType<DateTime>();
Map(u => u.dtLastLogin).CustomType<DateTime>();
Map(u => u.tipo).CustomType<int>();
Map(u => u.imagem);
Map(u => u.loginBy).CustomType<int>();
Map(u => u.idFacebook);
}
}
HQL Query
public class UsuarioDAO : GenericDAO<Usuario>{
/** retorna todos os objetos */
public IList<Usuario> findAll(){
ISession _session = getSession();
IList<Usuario> list = _session.CreateQuery("FROM Usuario u ORDER BY u.nome")
.SetCacheable(true).SetCacheMode(CacheMode.Normal)
.List<Usuario>();
return list;
}
A UseSecondLevelCache call is very likely missing (xml configuration parameter cache.use_second_level_cache).
HashtableCacheProvider is not intended for production use, only for test. Choose another one.
Transactions do not seem used. At first data change done outside of a transaction, the second level cache will be disabled. Better transacted all session usages.
A cache.default_expiration should be configured. This is an integer, in seconds.
You may use session statistics to check if the cache is used. Enable them on the session factory.
sessionFactory.Statistics.IsStatisticsEnabled = true;
// Do your stuff then consult the statistics on the session factory.
Avoid letting them enabled in production, this incurs some overhead.
Additional notes:
If you have some mapped collection you wish to cache, you will have to enable caching for them in their mapping.
Caching works better with lazy-loading. Eager loading may cause cached entities to be reloaded from database instead of being loaded from cache.

Getting started with nhibernate, informix and fluentmapping

I need to configure NHibernate 3.1 to target an informix 11.50 database in an asp.net 4.0 application
using Fluent NHibernate for mappings.
I have this connection string: jdbc:informix-sqli://server:1530/database:informixserver=lufi_tcp
and I have the user an pass. I can connect to to the database using dbvisualizer.
I tray some examples of configuracion that I find on the Internet but it dosen't work.
Can someone get my a link or informacion about what I need to do for
configure nhibernate with fluent to target an informix database (for dummies, please.)
S.O: Windows 8 64 bits
Thanks you in advance.
More information:
I Build the session factory in this way:
class FluentNHibernateLocalSessionFactory : LocalSessionFactoryObject
{
public string[] FluentNhibernateMappingAssemblies { get; set; }
protected override ISessionFactory NewSessionFactory(Configuration config)
{
return Fluently.Configure()
.Database(
IfxSQLIConfiguration
.Informix1000
.Provider<NHibernate.Connection.DriverConnectionProvider>()
.Driver<NHibernate.Driver.IfxDriver>()
.Dialect<NHibernate.Dialect.InformixDialect>()
.ConnectionString("Database=myDatabase;Server=myServer:1530;Persist Security Info=True;Authentication=Server;uid=myUser;password=myPass;")
.ShowSql()
)
.Mappings(m =>
{
foreach (string assemblyName in FluentNhibernateMappingAssemblies)
m.FluentMappings.AddFromAssembly(Assembly.Load(assemblyName));
})
.BuildConfiguration()
.BuildSessionFactory();
}
}
The error I get:
{"Could not create the driver from NHibernate.Driver.IfxDriver, NHibernate, Version=3.1.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4."}
You have to add a reference to IBM.Data.Informix otherwise the driver will throw this exception. To do so you have to add a reference to IBM.Data.Informix.dll to the project which is running your code above.

Warning when upgrading Fluent 1.2 from NH 3.0 to 3.1 -- ProxyFactoryFactory is obsolete, moved to

I'm fairly new to NHibernate and Fluent NHibernate and I've been using Fluent 1.2 for NH 3.0 for about 6 months. I just upgraded to Fluent 1.2 for NH 3.1. Now I'm getting a warning (in Visual Studio), and I've tried to fix it but no luck. I could use some help...
In my Global.asax file, I Fluently-configure NHibernate:
var nhConfig = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(connstr => connstr.FromConnectionStringWithKey("MyDatabase"))
.ProxyFactoryFactory<ProxyFactoryFactory>().AdoNetBatchSize(100))
.Mappings(mappings => mappings.FluentMappings.AddFromAssemblyOf<MyClass>())
.ExposeConfiguration(c => c.Properties.Add("current_session_context_class", "web"))
.BuildConfiguration();
I'm getting a warning on the line:
.ProxyFactoryFactory<ProxyFactoryFactory>().AdoNetBatchSize(100))
Here's the warning:
FluentNHibernate.Cfg.Db.PersistenceConfiguration<FluentNHibernate.Cfg.Db.MsSqlConfiguration,
FluentNHibernate.Cfg.Db.MsSqlConnectionStringBuilder>.ProxyFactoryFactory<TProxyFactoryFactor y>()'
is obsolete: 'Moved to FluentConfiguration Fluently.Configure().ProxyFactoryFactory(...))'
I think I need to use the FluentlyConfigure().ProxyFactoryFactory(), but the help/intellisense for that method says it's only for NH 2.1.
What should I be doing in my configuration to eliminate this warning and not use obsolete/deprecated methods?
Thanks.
In the last couple of FluentNHibernate builds, the ProxyFactoryFactory method was moved out of Database to directly off of Configure. Try this:
var nhConfig = Fluently.Configure()
.ProxyFactoryFactory<ProxyFactoryFactory>()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("MyDatabase").AdoNetBatchSize(100))
.Mappings(mappings => mappings.FluentMappings.AddFromAssemblyOf<MyClass>())
.ExposeConfiguration(c => c.Properties.Add("current_session_context_class", "web"))
.BuildConfiguration();

Mixing DB configuration from file with Fluent NHibernate mapping

I stumbled upon the following problem: I wanted to configure the DB from config file but the mappings fluently (love it!) The configuration code looks like this:
var cfg = new Configuration();
cfg.Configure();
var fluentCfg = Fluently.Configure(cfg)
.Mappings(
m => m
.FluentMapping
.AddFromAssembly(Assembly.GetExecutingAssembly));
However the config file has a property:
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.LinFu.ProxyFactoryFactory,
NHibernate.ByteCode.LinFu
</property>
and after the cfg.Configure(); all looks good the configuration points to the LinFu bytecode provider BUT after the third line I see the configuration changed to using Castle. I looked in the Fluent's code and I might be wrong but it looks like they are overriding this property in PersistenceConfiguration.cs(line 50) in the constructor of PersistenceConfiguration:
values[ProxyFactoryFactoryClassKey] = DefaultProxyFactoryFactoryClassName;
Does Fluent require Castle? Or may be I am doing something wrong or maybe this is just a bug?
Thank you.
I don't know if this is what you're looking for, but it might help you out. You can expose the configuration and make any changes that you need to, in code.
var cfg = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionStringName")).ShowSql())
.Mappings(m =>
{
m.FluentMappings.AddFromAssemblyOf<MapMarker>();
m.FluentMappings.Conventions.AddFromAssemblyOf<ConventionMarker>();
})
.ExposeConfiguration(x => x.SetProperty("proxyfactory.factory_class", "NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu"));
There's a ProxyFactoryFactory method chained off Configure.
Fluently.Configure()
.ProxyFactoryFactory(name);
If you're not on 1.2, I believe it's under the Database call (see RexM's answer).

NHibernate Configuration reference at runtime

Is there a way to get a reference to NHibernate Configuration at the runtime? I need it for SchemaExport().
Update: I am using StructureMap with FluentNHibernate to set it up, but I just want to know if I can get it from SessionFactory or some other object, after SessionFactory has been initialized, without having to rewrite setup in ioc to hold on to reference to Configuration.
Ok, here is how I did it.
ForRequestedType<FluentConfiguration>()
.CacheBy(InstanceScope.Singleton)
.TheDefault.Is.ConstructedBy(
()=>Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005
.AdoNetBatchSize(10)
.Driver("NHibernate.Driver.SqlClientDriver")
.ProxyFactoryFactory("NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle")
.UseOuterJoin()
.ConnectionString(#"Server=.\SQLEXPRESS;User Id=epitka;Password=password;Database=dnn49;")
.ShowSql()
.CurrentSessionContext("thread_static")) // CHANGE THIS FOR WEB
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<MetaProject>())
.ExposeConfiguration(
cfg =>{
cfg.SetProperty(
Environment.TransactionStrategy,
typeof (AdoNetTransactionFactory).FullName);
cfg.SetProperty(Environment.GenerateStatistics, "true"); //REMOVE FOR LIVE
})
)
.WithName("SharMod_FluentConfiguration");
ForRequestedType<Configuration>()
.TheDefault.Is.ConstructedBy(
() =>
{
var fc =ObjectFactory.GetInstance<FluentConfiguration>();
return fc.BuildConfiguration();
})
.WithName("SharpMod_Configuration");
//SharpMod_SessionFactory
ForRequestedType<ISessionFactory>()
.CacheBy(InstanceScope.Singleton)
.AddInstances(x => x.ConstructedBy(() =>
ObjectFactory.GetNamedInstance<FluentConfiguration>("SharMod_FluentConfiguration")
.BuildSessionFactory())
.WithName("SharpMod_SessionFactory"));
Now to get it I just do:
var cfg = ObjectFactory.GetNamedInstance<Configuration>("SharpMod_Configuration");