I've been working on a WCF service that uses fluent and syscache2. I've pretty much read every article on SO regarding my current dilemma; I've had no luck.
I am trying to set the expiration time for my second-level cache. Whatever value I set seems to be ignored and the default value of 5 minutes is used to expire the cache.
Fluent configuration:
Note: contextClass is just a descriptor class holding values passed to the configuration.
var cfg = Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008
.ConnectionString(c => c.Is(connectionString))
.ShowSql()
)
.Diagnostics(d => d.Enable())
.Cache(c => c
.UseQueryCache()
.ProviderClass(typeof(NHibernate.Caches.SysCache2.SysCacheProvider).AssemblyQualifiedName))
.Mappings(m => m
.FluentMappings
.AddFromAssembly(assembly))
.ExposeConfiguration(x =>
{
x.SetProperty(NHibernate.Cfg.Environment.CurrentSessionContextClass, contextClass.Id);
x.SetProperty(NHibernate.Cfg.Environment.PrepareSql, contextClass.PrepareSql); //set prepare_sql true/false
x.SetProperty(NHibernate.Cfg.Environment.CacheDefaultExpiration, contextClass.ExpireL2Cache); //set default expiration in seconds
});
I also have the app.config file set up as following:
<configSections>
<section name="syscache" type="NHibernate.Caches.SysCache2.SysCacheSection, NHibernate.Caches.SysCache2"/>
</configSections>
<syscache>
<cache expiration="600" priority="5" />
</syscache>
There was a variant of the app.config which had a syscache section that used regions but that didn't work either.
Anyone have any suggestions on ideas?
Thanks
I've always used this without problems:
.ExposeConfiguration (cfg => {
cfg.Properties.Add ("expiration", "900");
})
Not sure if Properties.Add behaves any differently than the SetProperty call you're using though.
It seems like if you're using a newer version of NHibernate you can lean on the new extension methods in the NHibernate.Cfg namespace for this as well (this would replace your entire .Cache call in fluent)
.ExposeConfiguration (cfg => {
cfg.SessionFactory().Caching.Through<SysCacheProvider>().WithDefaultExpiration(900);
})
Doing some reading I found this:
cache.default_expiration or expiration (Int32): since NH Contrib 2.1 cache.default_expiration is the new setting name that should be used instead of expiration to specify number of seconds after which the cache item must be invalidated. Default value is 300 seconds. The old name is still supported for backward compatibility.
So the property name is probably not your issue (wondering now if the "expiration" key that I used was maybe specific to the memcache provider as well, though it seemed to work with syscache).
Related
I am using NodaTime's LocalDate in RavenDB index.
Here is an example of the index:
public class TaskIndex : AbstractIndexCreationTask<ScheduleTask>
{
public TaskIndex()
{
Map = tasks => from task in tasks
select new
{
task.Name,
PlannedStartDate = task.PlannedStartDate.AsLocalDate().Resolve(),
PlannedDueDate = task.PlannedDueDate.AsLocalDate().Resolve()
};
Index(x => x.Name, FieldIndexing.Analyzed);
Store(x => x.Name, FieldStorage.Yes);
TermVector(x => x.Name, FieldTermVector.WithPositionsAndOffsets);
}
}
I installed RavenDB-NodaTime bundle as described here.
Here is a piece of code I use to install index:
var assembly = AppDomain.CurrentDomain.Load(new AssemblyName
{
Name = "cs.Scheduling"
});
var catalog = new AssemblyCatalog(assembly);
var provider = new CompositionContainer(catalog);
var commands = documentStore.DatabaseCommands.ForDatabase(dbName);
IndexCreation.CreateIndexes(provider, commands, documentStore.Conventions);
documentStore is configured with default database, but then I use it to install index to different (tenant) database name of which comes in dbName.
During the installation of the index I got an exception: The name 'NodaTimeField' does not exist in the current context.
I have one default database which is completely different from database I try to install index for. So basically the case is similar to one described here but I am using standalone version of RavenDB server.
I tried to find out how I can do suggested there but was not able to do that:
embeddableDocumentStore.ServerIfEmbedded.Options.DatabaseLandlord.SetupTenantConfiguration += configuration =>
{
configuration.Catalog.Catalogs.Add(new TypeCatalog(typeof(DeleteOnConflict)));
configuration.Catalog.Catalogs.Add(new TypeCatalog(typeof(PutOnConflict)));
};
Version of RavenDB I am using is 2.5.2956.
RavenDB.Client.NodaTime - 2.5.10.
Hope for your help. Thanks.
In my case that was a very silly mistake. When I was installing RavenDB server some time ago I installed it into non-default destination. Later some RavenDB updates were installed into default destination (i.e. \Program Files (x86)\RavenDB). And when I was installing RavenDB-NodaTime bundle I put it into incorrect destination (\Program Files (x86)\RavenDB).
After detecting this issue and configuring RavenDB server in my correct destination properly an error described in the heading has gone away.
Hope this answer can help somebody else.
P.S. Later there was a deserialization error during reading data from db (RavenDB was not aware of how to deserialize date from string in "yyyy-MM-dd" format to LocalDate object) which I fixed by calling store.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); after store.Initialize(); call as Steven suggested in his answer.
I believe the answer is that your tenant database does not have the bundle "activated" Your database document (under settings in Raven 3) should have something like
"Raven/ActiveBundles": "Encryption;Compression;NodaTime"
Also you must call
store.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
I call this after store.Initialize(). Once you do both of these things, you may have to fix existing data by re-saving your documents (not sure if there is another way). New data will be properly stored like '2016-2-3' format which should make your index return data.
I have a need to fluently configure nhibernate in my S#arp application so that I can use a custom NHibernate.Search directory for each of my tenants in a multi-tenant app.
However I have googled for hours looking for a solution but can't seem to find anything current that works.
Thanks,
Paul
I haven't tried this myself, but AddConfiguration takes a dictionary of cfgProperties, which I guess you can pass the tenant specific hibernate.search.default.indexBase value to.
I had a look at this, adding the key as described above will cause a problem if you attempt to use CfgHelper.LoadConfiguration() since it will return null.
But you can configure NHSearch to use different directories for each factory using the factory key:
<nhs-configuration xmlns="urn:nhs-configuration-1.0">
<search-factory sessionFactoryName="YOUR_TENANT1_FACTORY_KEY">
<property name="hibernate.search.default.indexBase">~\IndexTenant1</property>
</search-factory>
<search-factory sessionFactoryName="YOUR_TENANT2_FACTORY_KEY">
<property name="hibernate.search.default.indexBase">~\Tenant2</property>
</search-factory>
</nhs-configuration>
If you are following instructions on
http://wiki.sharparchitecture.net/Default.aspx?Page=NHibSearch
You would need to change the method GetIndexDirectory to
private string GetIndexDirectory() {
INHSConfigCollection nhsConfigCollection = CfgHelper.LoadConfiguration();
string factoryKey = SessionFactoryAttribute.GetKeyFrom(this); // Change this with however you get the factory key for your tenants,
string property = nhsConfigCollection.GetConfiguration(factoryKey).Properties["hibernate.search.default.indexBase"];
var fi = new FileInfo(property);
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fi.Name);
}
i'm trying to get my head around 2nd Level Caching in Fluent NHibernate. So far i have done the following:
Added a reference to the caching dll
Added the following when i create my session factory:
c.SetProperty("cache.provider_class", "NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache");
c.SetProperty("cache.use_second_level_cache", "true");
c.SetProperty("cache.use_query_cache", "true");
Added Cache.ReadWrite(); against all entities i wish to cache in ClassMap file e.g.
public class CountryMap : ClassMap {
public CountryMap() {
Table("Countries");
Id(x => x.CountryID);
Map(x => x.CountryName);
Cache.ReadWrite();
}
}
Now i assumed that anytime i try to get an entity which has Cache.ReadWrite() in the mapping it would cache it for the duration of the session factory (singleton). However it appears that this is not the case as the database is hit on every request. Here's a couple questions i have:
What does the CacheMode property on the session do? My session lasts for the duration of a web request. Should i set this when i create the session and if so what should i set it to?
I read somewhere that the cache is not updated unless a commit is made. I only commit data when i'm inserting/updating information in the database. For example if i have a simple page with a list of countries i would grab all the data needed but wouldn't commit the data as i don't need to make any changes. Does this mean this data won't be cached? I'm sure i've read this wrong as this would mean data is only cached once it is added the database.
I'd appreciate it if you could help. Thanks
Here is a very good explanation for second level cache with nhibernate.
You have to use transactions for the 2nd level cache to be used.
I have been successfully using NHibernate, but now I am trying to move to Fluent NHibernate. I have created all of my mapping files and set up my session manager to use a Fluent Configuration. I then run my application and it runs successfully, but no data is returned.
There are no errors or any indication that there is a problem, but nothing runs.
when using NHibernate, if I don't set my hbm xml files as an embedded resource, this same thing happens. This makes me wonder what I have to set my Map classes to. Right now, they are just set to Compile, and they are compiled into the dll, which I can see by disassembling it.
Does anyone have any thoughts as to what may be happening here?
Thanks
private ISessionFactory GetSessionFactory()
{
return Fluently.Configure()
.Database(
IfxOdbcConfiguration
.Informix1000
.ConnectionString("Provider=Ifxoledbc.2;Password=mypass;Persist Security Info=True;User ID=myuser;Data Source=mysource")
.Dialect<InformixDialect1000>()
.ProxyFactoryFactory<ProxyFactoryFactory>()
.Driver<OleDbDriver>()
.ShowSql()
)
.Mappings(
x => x.FluentMappings.AddFromAssembly(System.Reflection.Assembly.GetExecutingAssembly())
//.ExportTo("C:\\mappings")
)
.BuildSessionFactory();
}
Does the executing assembly contain the fluent mapping classes? I would try:
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<MappedType>())
Where MappedType is a class that has a fluent mapping.
They should just be set to compile, that's fine. Nothing special needed here. The problem is most likely in your fluent configuration rather than the mapping.
I am trying to get Fluent nHibernate to generate mappings so I can take a look at the files and the sql.
My code is based on this post and on what I can glean from the documentation.
Fluent mapping - entities and classmaps in different assemblies
I am using the latest code from git.
Here’s my config code:
Configuration cfg = new Configuration();
var ft = Fluently.Configure(cfg);
//DbConnection by fluent
ft.Database
(
MsSqlConfiguration
.MsSql2008
.ConnectionString("……")
.ShowSql()
.UseReflectionOptimizer()
);
//get mapping files.
ft.Mappings(m =>
{
//set up the mapping locations
m.FluentMappings.AddFromAssemblyOf<Entity>()
.ExportTo(#"C:\temp");
m.Apply(cfg);
});
I also tried:
var sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration
.MsSql2008
.ShowSql()
.ConnectionString(“……"))
.Mappings(p => p.FluentMappings
.AddFromAssemblyOf<Entity>()
.ExportTo(#"c:\temp\"))
.BuildSessionFactory();
I have verified that the connection string is correct.
The issue is that no mapping files show up in the ExportTo folder and no sql code shows up in the output window or in the log file. No errors or exceptions are generated either.
I have no idea where to go from here.
Thank you in advance.
Rick
I think you have to actually spin up some objects to get the maps written out. If I remember correctly, this is not done at config time.