SharpArchitecture: Using FNH's ClassMaps instead of auto mapping - nhibernate

I need to use ClassMaps instead of auto mapping because of legacy database. But I don't see how to tune SharpArch to use them. I tried to remove AutoPersistentModelGenerator and use the following code in the InitializeNHibernateSession method:
var config = NHibernateSession.Init(webSessionStorage,
new[]{"ApplicationConfiguration.Models.dll"});
Fluently.Configure(config)
.Mappings(m =>
{
m.FluentMappings.AddFromAssemblyOf<ConfigSchema>();
});
But I always get MappingException - "No persister for: ConfigSchema" when trying to work with the ConfigSchema.
Has anyone tried to do this?
Edit:
ConfigSchema is a part of domain model.

I'm stupid. Fluently.Configure(config) generates a new config for NHibernate. So it will never be used in my scenario. All I was need is to use the following code in the AutoPersistentModelGenerator:
public AutoPersistenceModel Generate()
{
var mappings = new AutoPersistenceModel();
mappings.AddMappingsFromAssembly(typeof(ConfigVersionMap).Assembly);
return mappings;
}

I'm not all that familiar with the S#arp project, but is ConfigSchema a type from you domain model? The generic argument T to AddFromAssemblyOf<T> should be a mapped class from your domain model.

Related

Serialization error with Elasticsearch NEST/C#

I'm using NEST to index my objects and I'm running into a Newtonsoft error on serialization. One of my objects has a self referencing loop. Would there be a way for me to access the JsonSerializer and change how it handles self-references without having to modify the source code?
You can register custom converters on your client:
public void AddConverter(JsonConverter converter)
{
this.IndexSerializationSettings.Converters.Add(converter);
this.SerializationSettings.Converters.Add(converter);
}
This might be of help.
There is no direct way to alter the JsonSerializerSettings used in the client though.
There is a new api now, take a look at:
var cs2 = new ConnectionSettings(new Uri("http://localhost:9200"))
.SetJsonSerializerSettingsModifier(settings => settings.TypeNameHandling = TypeNameHandling.None)
.EnableTrace();
Thanks for adding the support!

NCommon + Fluent NHibernate + Multiple Databases?

I'm trying to wire NCommon and NH to multiple databases via the guidance at http://codeinsanity.com (see 'Configuring NCommon for multiple database support') and it works via the fluent approach suggested, below:
var configuration = NCommon.Configure.Using(adapter).ConfigureState<DefaultStateConfiguration>();
configuration.ConfigureData<NHConfiguration>(config => config.WithSessionFactory(() => _sessionFactories[0]).WithSessionFactory(() => _sessionFactories[1]));
This works as expected but as you can see the sessionFactories are hardcoded. What I'd really like to do is something like this:
foreach(ISessionFactory sessionFactory in _sessionFactories)
{
configuration.ConfigureData<NHConfiguration>(config => config.WithSessionFactory(() => sessionFactory));
}
But this throws the following exception:
Component NCommon.Data.NHibernate.NHUnitOfWorkFactory could not be registered. There is already a component with that name. Did you want to modify the existing component instead? If not, make sure you specify a unique name.
My hope is there's a proper way to wire-up n-SessionFactories without hardcoding them - but I'm just not seeing a solution. Any advice?
I thought I got this to work by delegating the SessionFactory piece to a method, as below:
configuration.ConfigureData<NHConfiguration>(config => ConfigureSessionFactories(config));
private void ConfigureSessionFactories(NHConfiguration configuration)
{
foreach (ISessionFactory sessionFactory in _sessionFactories)
{
configuration.WithSessionFactory(() => sessionFactory);
}
}
However, that only appears to be a solution. Say you have multiple session factories, you can use all of them to query, but only the last-added session factory will hit the database and return results. Queries against the other session factories will never hit the actual database and will return zero entities.
The only way I've been able to get this to work is:
configuration.ConfigureData<NHConfiguration>(config => config.WithSessionFactory(() => _sessionFactories[0]).WithSessionFactory(() => _sessionFactories[1]));
I'd rather not hard-code that though.. I'd much rather iterate over a loop of n-session factories... does anyone have an idea of how to accomplish this?

Set default max_lo for NHibernate HiLo generator?

Is there any way to set a default value for max_lo that will take effect for all mapped entities? All of my entities are currently mapped via Xml. I know the default is 32678, but I would like to reduce this to 1000.
I've had a look through the NH configuration xsd and I can't see any settings in there. I think that you should be able to achieve this ok if you are mapping by code, but I am currently using Xml and don't fancy changing across.
Thanks.
you can also override the value on SessionFactory generation, which is only done once:
private void InitSessionFactory()
{
var cfg = new Configuration().Configure();
foreach (var cm in cfg.ClassMappings) {
if (cm.Identifier.IsSimpleValue) {
var simpleVal = cm.Identifier as SimpleValue;
if (simpleVal.IdentifierGeneratorStrategy == "hilo"){
simpleVal.IdentifierGeneratorProperties["max_lo"] = "1000";
}
}
}
sessionFactory = cfg.BuildSessionFactory();
}
this NH2 code so for NH3 there might be some differences
No way to configure default/global from hbm. Int16.MaxValue is simply hardcoded in NHibernate (as of 3.2). TableHiLoGenerator source:
public override void Configure(IType type, ...)
{
...
maxLo = PropertiesHelper.GetInt64(MaxLo, parms, Int16.MaxValue);
...
}
I guess you can open feature request here.
It looks like it may be possible to do this by extending the NH hilo generator as per http://daniel.wertheim.se/2011/03/08/nhibernate-custom-id-generator/

NHibernate mapping error in legacy mapping

I've inherited a large set of NHibernate mappings that live in an existing, functional application. I've branched this application to develop some new features, and while I do so I'm also extending the testing infrastructure to allow for a more TDD-like approach. But now I've hit a wall in one of my integration tests...
I have a class with test data, which I insert prior to the integration test. In the method that inserts these, I get the following exception:
NHibernate.PropertyAccessException: Invalid Cast (check your mapping for property type mismatches); setter of Domain.Entities.Project ---> System.InvalidCastException: Unable to cast object of type 'System.Object' to type 'Domain.Entities.ProjectModules'.
and I can't figure out why. I have two Project instances that I try to persist in the database on setup, both defined like this:
new Project("2023", "projeName", "projaddr")
{
PrincipalOwner = UserOne, // UserOne and Office are other properties
Office = Office,
// I've tried just not instantiating this too - gave the same exception
ProjectModules = new ProjectModules
{
HasModuleOne = false,
HasModuleTwo = false
});
});
The (relevant part of the) Fluent NHibernate mapping looks like this:
Component(m => m.ProjectModules, c =>
{
c.LazyLoad();
c.Map(x => x.HasModuleOne)
.Column("ModuleOne").Not.Nullable().Default("0");
c.Map(x => x.HasModuleTwo)
.Column("ModuleTwo").Not.Nullable().Default("0");
});
I've solved this - for some reason, NHibernate didn't like when the component mapping was specified inline in the mapping for Projects, but if I moved the mapping to a separate class ComponentMap<T> it worked. So I changed the problematic lines to
Component(p => p.ProjectModules);
and added the following class to my mappings assembly:
public class ProjectModulesMap : ComponentMap<ProjectModules>
{
LazyLoad.Always();
Map(pm => pm.ModuleOne);
Map(pm => pm.ModuleTwo);
}
Then everything worked as I would have expected it to from the start.

How to export hbm xml files using s#arparchitecture with fluent mappings

This question was asked before but the answers all show how to export the hbm files from fluentnhibernate. We are using S#arpArchitecture which wraps fluent. I am able to export the schema but what I really want is the xml files to troubleshoot errors. I've done this using FNH before but adding S#arp to the mix has complicated things where I cannot figure it out.
I've found this question asked on several forums, but I can't find one that shows how to get the mapping files.
Here is how I do it in one of my projects:
[TestMethod]
public void CreateSchema()
{
var mappingOutput = ConfigurationManager.AppSettings["xmlMappingOutputDirectory"];
var sqlOutput = ConfigurationManager.AppSettings["sqlOutputDirectory"];
Configuration cfg = new Configuration().Configure();
var persistenceModel = new PersistenceModel();
persistenceModel.AddMappingsFromAssembly(Assembly.Load("ProjectName.Data"));
persistenceModel.Configure(cfg);
persistenceModel.WriteMappingsTo(mappingOutput);
new SchemaExport(cfg).SetOutputFile(sqlOutput).Create(true, false);
}
You will need to set the two keys in the your app config or provide values directly for them.
http://wiki.fluentnhibernate.org/Fluent_configuration#Exporting_mappings
In the Mappings call, you can do the following:
.Mappings(m =>
{
m.FluentMappings
.AddFromAssemblyOf<YourEntity>()
.ExportTo(#"C:\your\export\path");
m.AutoMappings
.Add(/* ... */)
.ExportTo(#"C:\your\export\path");
})
As it turns out that only works if you're not using automapping. Here's the solution if you're using automapping:
public void CanGenerateMappingFiles()
{
DirectoryInfo directoryInfo = new DirectoryInfo("../../../../db/mappings");
if (!directoryInfo.Exists)
directoryInfo.Create();
Configuration cfg = new Configuration().Configure();
var autoPersistenceodel = new AutoPersistenceModelGenerator().Generate();
autoPersistenceodel.Configure(cfg);
autoPersistenceodel.AddMappingsFromAssembly(Assembly.Load("TrackerI9.Data"));
autoPersistenceodel.WriteMappingsTo(directoryInfo.FullName);
}
You'll have to make sure that your configuration is set up correctly and that you choose an appropriate location for the directory, but otherwise this should work. It did for me.