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

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.

Related

Is it possible to distribute NHibernate-by-Code-Mappings over several classes?

Is it possible to distribute a NHibernate-by-Code-Mapping over several classes?
E.g.
public class EntityMap1 : ClassMapping<Entity> {
Id(x => x.Id);
Property(x => x.PropertyOne);
}
public class EntityMap2 : ClassMapping<Entity> {
Property(x => x.PropertyTwo);
}
I tried it but the mapping of PropertyTwo was missing in the generated HBML. Is there some way to achieve this?
I don't believe NHibernate would be able to compile both together to create a singular mapping. If the goal is to use a different set of mappings in one app versus another, you need to simply create two different mappings. If the goal is to have subclasses, there is a SubclassMapping interface you can extend.
Edit:
In looking over my notes, an extension to my answer about creating a different set of mappings would be the case where you have some feature plugged into your app that needs a different (sometimes more, sometimes less involved) mapping. To do this you need to have NHibernate generate them separately and add them to the configuration separately. Using conventions, this creates two separate sets of mappings (which contain some overlapping, but differently mapped, entites) that are plugged into one configuration:
NHibernateConfiguration.BeforeBindMapping += (sender, args) => args.Mapping.autoimport = false;
var pluginMappings = new PluginMapper().Mappings;
foreach (var hbmMapping in pluginMappings)
NHibernateConfiguration.AddDeserializedMapping(hbmMapping, "PluginModel");
var mainAppMappings = new AppMapper().Mappings;
foreach (var hbmMapping in mainAppMappings)
NHibernateConfiguration.AddDeserializedMapping(hbmMapping, "AppModel");
As described in my comment to Fourth's answer the goal was that a plugin can modify the mapping of the main application, i.e. EntityMap1 would reside in the main program and EntityMap2 in the plugin. I could avoid this problem by only keeping EntityMap1 and manually modifying the generated XML.
var domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
var oldMappingXml = domainMapping.AsString();
var newMappingXml = ModifyMappings(oldMappingXml);
configuration.AddXmlString(newMappingXml);
oldMappingXml contains the XML generated by the mappings defined in the main application and ModifyMappings adds the changes required by the plugin. This is possible because the changes required by the plugins are well defined and follow the same algorithm for all plugins.

Generate HBM files using mapping by code

I'm using NHibernate mapping by code and I'm creating the session factory in this way:
var mapper = new ModelMapper();
mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes());
HbmMapping domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
const bool executeScript = false;
var configuration = new Configuration();
configuration.DataBaseIntegration(c =>
{
c.Dialect<MsSql2005Dialect>();
c.ConnectionString =
ConfigurationManager.ConnectionStrings["ShopConnectionString"]
.ConnectionString;
c.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
});
configuration.AddMapping(domainMapping);
_sessionFactory = configuration.BuildSessionFactory();
I need to get the corresponding HBM files.
How can I achieve that?
Two ways:-
//This will write all the XML into the bin/mappings folder
mapper.CompileMappingForEachExplicitlyAddedEntity().WriteAllXmlMapping();
be careful of this method above as your asp.net app will recycle as changes are detected in your bin folder, another way is:-
var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
//you could add a breakpoint here!
var mappingXml = mapping.AsString();
Use the AsString() extension method:
domainMapping.AsString()
It will give you the xml which you can save into a file. You can call that method e.g. before you build the SessionFactory.

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/

SharpArchitecture: Using FNH's ClassMaps instead of auto mapping

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.

Combine Fluent and XML mapping for NHibnernate

I just fell in love with NHibernate and the fluent interface. The latter enables very nice mappings with refactoring support (no more need for xml files).
But nobody is perfect, so I am missing the many-to-any mapping in fluent. Does anybody know if it is already there? If so, a simple line of code would be nice.
But to stick to the header of the question, is there any way to combine fluent and normal NHibernate mapping.
Currently I use the following lines for my test setup WITH fluent, and the second code block for my test WITHOUT fluent (with XML mappings). How can I tell fluent to use fluent IF AVAILABLE and XML otherwise...
var cfg = new Configuration();
cfg.AddProperties(MsSqlConfiguration.MsSql2005.ConnectionString.Is(_testConnectionstring).ToProperties());
cfg.AddMappingsFromAssembly(typeof(CatMap).Assembly);
new SchemaExport(cfg).Create(true, true);
var persistenceModel = new PersistenceModel();
persistenceModel.addMappingsFromAssembly(typeof(CatMap).Assembly);
IDictionary<string, string> properties = MsSqlConfiguration.MsSql2005.UseOuterJoin().ShowSql().ConnectionString.Is(_testConnectionstring).ToProperties();
properties.Add("command_timeout", "340");
session = new SessionSource(properties, persistenceModel).CreateSession();
Without Fluent...
config = new Configuration();
IDictionary props = new Hashtable();
props["connection.provider"] = "NHibernate.Connection.DriverConnectionProvider";
props["dialect"] = "NHibernate.Dialect.MsSql2005Dialect";
props["connection.driver_class"] = "NHibernate.Driver.SqlClientDriver";
props["connection.connection_string"] = "Server=localhost;initial catalog=Debug;Integrated Security=SSPI";
props["show_sql"] = "true";
foreach (DictionaryEntry de in props)
{
config.SetProperty(de.Key.ToString(), de.Value.ToString());
}
config.AddAssembly(typeof(CatMap).Assembly);
SchemaExport se = new SchemaExport(config);
se.Create(true, true);
factory = config.BuildSessionFactory();
session = factory.OpenSession();
That's it...
Chris
PS: I really like this site, the GUI is perfect, and the quality of all articles is incredible. I think it will be huge :-) Have to register...
ManyToAny's currently aren't implemented (as of time of writing).
Regarding your setup for fluent and non-fluent mappings, you're almost there with your first example.
var cfg = MsSqlConfiguration.MsSql2005
.ConnectionString.Is(_testConnectionstring)
.ConfigureProperties(new Configuration());
cfg.AddMappingsFromAssembly(typeof(CatMap).Assembly); // loads hbm.xml files
var model = new PersistenceModel();
model.addMappingsFromAssembly(typeof(CatMap).Assembly); // loads fluent mappings
mode.Configure(cfg);
new SchemaExport(cfg).Create(true, true);
The main difference is that the SchemaExport is last. I assume your first example was actually loading the fluent mappings, but it'd already created the schema by that point.
You can do exactly what you want to do entirely within Fluent NHibernate.
The following code will use Fluent NHibernate syntax to fluently configure a session factory that looks for HBM (xml) mapping files, fluent mappings, and conventions from multiple possible assemblies.
var _mappingAssemblies = new Assembly[] { typeof(CatMap).Assembly };
var _autoPersistenceModel = CreateAutoPersistenceModel();
Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(_testConnectionstring))
.Mappings(m =>
{
foreach (var assembly in _mappingAssemblies)
{
m.HbmMappings.AddFromAssembly(assembly);
m.FluentMappings.AddFromAssembly(assembly)
.Conventions.AddAssembly(assembly);
}
m.AutoMappings.Add(_autoPersistenceModel );
})
.ExposeConfiguration(c => c.SetProperty("command_timeout", "340"))
.BuildSessionFactory();
There are many other options available to you as well: Fluent NHibernate Database Configuration
Mapping from Foo to Baa:
HasManyToMany< Baa > ( x => Baas )
.AsBag ( ) //can also be .AsSet()
.WithTableName ( "foobar" )
.WithParentKeyColumn ( "fooId" )
.WithChildKeyColumn ( "barId" ) ;
Check out the examples in ClassMapXmlCreationTester - they also show what the default column names are.