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");
Related
I have a problem when I am using MassTransit v5.1.5 with the default ASP.NET Core DI. I have the following code:
var consumers = typeof(CompanyApplicationService).Assembly
.GetTypes()
.Where(t => typeof(IConsumer).IsAssignableFrom(t))
.ToList();
consumers.ForEach(
c => services.AddSingleton(typeof(IConsumer), c));
cqrsConfig.ServiceCollectionConfig = (x) =>
{
consumers.ForEach(consumer => x.AddConsumer<consumer>());
};
So I have a separate assembly where my implementations of IConsumer<T> are. I have those consumers loaded into a list, but when I try to add them using the MassTransit.ExtensionsDependencyInjectionIntegration.IServiceCollectionConfigurator.AddConsumer<T>() method I cannot pass the type that I have previously loaded. So any ideas on this?
I have tried to register the consumers like:
cqrsConfig.InMemoryBusConfig = (c) =>
{
var host = c.Host;
c.ReceiveEndpoint(busName, ep =>
{
ep.LoadFrom(services.BuildServiceProvider());
});
};
but that also doesn't work for me.
There's more than one thing that is wrong here.
In order to know, which message to handle, MassTransit needs to know the generic interface type of the consumer. You, however, register all consumers as IConsumer, which is apparently wrong.
Consumers are by definition isolated to the message scope. So, consumers are instantiated and disposed for each message, and, therefore, cannot be singletons.
You need to register your consumers like it is described in the documentation:
services.AddScoped<OrderConsumer>();
or
services.AddMassTransit(x =>
{
x.AddConsumer<OrderConsumer>();
});
When consumers are added to the service collection, you also need to register the bus as it is shown in the documentation, so you use the service provider delegate:
services.AddSingleton(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host("localhost", "/", h => { });
cfg.ReceiveEndpoint(host, "submit-order", e =>
{
e.LoadFrom(provider);
});
}));
services.AddSingleton<IBus>(provider => provider.GetRequiredService<IBusControl>());
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.
I'm trying to use FluentNHibernate in ServiceStack with the Funq IoC container on a session-per-request basis and I'm running into a problem where upon the second request to my service, I get an ObjectDisposedException. Shouldn't Funq create a new Session for each request?
My understanding is that by using ReusedWithin(ReuseScope.Request) in Funq, each request would get a new ISession, but that's only happening for the first request. In my AppHost I have the following:
public static NH.ISession CurrentSession
{
get
{
SessionFactory = GetFactory();
NH.ISession session = SessionFactory.OpenSession();
return session;
}
}
private static NH.ISessionFactory GetFactory()
{
return Fluently.Configure().Database(MsSqlConfiguration.MsSql2008
.ConnectionString(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString)).Mappings(m =>
{ m.FluentMappings.AddFromAssemblyOf<Case>(); })
.BuildSessionFactory();
}
And the registration with the container:
container.Register<NH.ISession>(c => CurrentSession).ReusedWithin(Funq.ReuseScope.Request);
container.Register<ILog>(c => LogManager.GetLogger(GetType()));
So I figured out what my problem was. When using a request scope of per-request in Funq for a NHibernate ISession, make sure the other services that depend on it are also scoped per-request or their backing dependency (ISesssion in this case) will be disposed of on the next request. I changed my container registration to the below:
container.Register<NH.ISession>(c => CurrentSession).ReusedWithin(Funq.ReuseScope.Request);
container.Register<ILog>(c => LogManager.GetLogger(GetType()));
container.Register<IRequestService>(c => new Services.RequestService(c.Resolve<NH.ISession>(), c.Resolve<ILog>())).ReusedWithin(Funq.ReuseScope.Request);
The key is that the Request service must also be scoped per-request.
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();
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.