How to verify if NHibernate hbm.xml are matching with a particular SQL schema? - sql

I had an ASP.NET MVC web application, using NHibernate as ORM on SQL Server 2008 R2. When we deployed to the server, we can update our database any time (some are ad-hoc changes).
The problem is when the database schema change, the application crashed because NHibernate .hbm.xml files are no longer matching with the DB schema.
How do I verify that my current *.hbm.xml file are matching with the database schema ? And how to detect the mismatch early in ASP.NET MVC ?

You can do the checking when application runs, could be in the global asax.
protected void Application_Start()
{
}
The connection string is the key to get the expected schema.
<property name="connection.connection_string">Server=.;Initial Catalog=TheExpectedSchema; ..</property>
First read the expected schema by reading it from nhibernate config and retrieve it from Initial Catalog part (if the database is oracle, probably use the User ID part).
NHibernate.Cfg.Configuration config = ...;
var conStr = config.Properties["connection.connection_string"];
var match = Regex.Match(conStr, "Initial Catalog *= *([^;]*) *");
var expectedSchema = match.Groups[1].Value;
Then read the actual schema by reading it from *.hbm.xml file.
<hibernate-mapping schema="TheActualSchema"
If the files are put under App_Data directory, read each file and use xml document to get the schema.
var appDataDir = new DirectoryInfo(HttpContext.Server.MapPath("~/App_Data"));
var files = appDataDir.GetFiles("*.hbm.xml");
foreach (var file in files)
{
var doc = new XmlDocument();
doc.Load(file.FullName);
var actualSchema = doc.DocumentElement.GetAttribute("schema");
if (actualSchema != expectedSchema)
{
// Proper handling here (an example would be throwing exception).
throw new Exception(string.Format("Expected schema: {0}, actual schema {1}", expectedSchema, actualSchema));
}
}

Related

nhibernate xml files are not getting mapped automatically

-----working Code
Configuration cfg = new Configuration().DataBaseIntegration(db =>
{
/// Connection String
}).AddFile(#"D:\Test_MVC_Web\NHibernet_DAL\Mapping\departments.hbm.xml");
-------
above code is working fine for me but currently mapping is done manually i have to mapped xml file automatically at the time of configuration
using (var session = _IUnitOfWork.Session)
{
IQuery query = session.GetNamedQuery("GetDepartmentDetails");
query.SetResultTransformer(Transformers.AliasToBean(typeof(departments)));
return query.List<departments>() as List<departments>;
}
when i run above above code its giving me error named query
because xml files are not getting mapped
departments.hbm.xml file should be Embedded Resource
departments.hbm.xml-->properties-->Build Action-->Embedded Resource

config nhibernate for oracle and sql in same application

i need to create switchable web.config file which can configure N Hibernate to work with either MS-SQL Server or Oracle
I'm having 2 configuration files and one web.config files
sqlcongif.config
oracleconfig.config
if i want only SQL config i need to point to sqlconfigure.config in web.config
or else only oracle i need to point oracleconfig.config
tried with child config and other web options .
i found that similar problem when we are having connection strings in web config files
is there any options we can do this ?
thanks in advance :)
This issue could be easily solved with a switch in code (Oracle or SQL server), at the place where we ask for a ISessionFactory.
We just have to pass the config name and the connection string key:
public ISessionFactory BuildFactory(
string configFileName
string connectionStringKey)
{
// full path to the config
var fullfileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory
, configFileName);
var document = System.Xml.Linq.XDocument.Load(fullfileName);
// NH configuration
var config = new NHibernate.Cfg.Configuration();
// feeded with all the setting in our config
using (var reader = document.CreateReader())
{
config.Configure(reader);
}
// read connection string from web.config
// ADVANTAGE: it could be even encrypted
var connectionStringFromWebConfig = ConfigurationManager
.ConnectionStrings[connectionStringKey].ConnectionString;
// use that web.config connection string
config.SetProperty("connection.connection_string", connectionStringFromWebConfig);
// create factory
NHibernate.ISessionFactory factory = config.BuildSessionFactory();
return factory;
}
And then we can call it like
var factory = BuildFactory("config/sqlconfigure.config", "sqlServerConnection")

How to import raven db with versioning bundle

I have a database with versioning bundle turned on. I make an export and then try to import the exported dump to newly created db. I get the exception "Modifying a historical revisionis not allowed". I found this question and answer from Ayende, that its by design. But how do I import data to an empty database if the versioning bundle was turned on and there are revisions in it?
For now I did the following thing: I make a new database without a versioning bundle, but with replication bundle in it. Import to that db(and it works), but I have a lot of duplicates if I perform search.
After that I create another new database, with replication and versioning bundle turned on. And I replicate from the db with duplicates this db. And it works, but it seems its a lot of things todo.
Am I doing the right thing? Is there an easier way to get your data from the dump?
I've had the same issue. The ONLY way I could get the import to work was to do the following:
Create DB with Versioning enabled (They recommend that DBs be created with any bundles that may be used).
Disable the versioning bundle. I've done this by editing the database settings and removing the bundle from the "Raven/ActiveBundles" setting.
Import your database.
Enable the versioning bundle. Just add the "Versioning" bundle back to the "Raven/ActiveBundles" setting.
If anyone has a better idea, I'd love to hear it. :)
The new version of RavenDb 3.0 give the permission to import with the Bundle already activated. So all the trick of disabling and enabling is not of any use anymore. But you might have new issues like Index not in synch with your revision or having the "versioning" not displayed in the Settings=>Versioning window.
To fix your versioning if they don't show in the versioning window but that they are visible in the System Documents, you need to add the Id individually or run some kind of code.
Option parameter for import since RavenDb 3.0.3745:
--disable-versioning-during-import
Fix of Versioning not containing an Id :
private void UpdateVersioning(string destinationRavenDbServer, string databaseName)
{
using (var documentStore = new DocumentStore { Url = destinationRavenDbServer, DefaultDatabase = databaseName })
{
documentStore.Initialize();
using (var session = documentStore.OpenSession())
{
var versioningInfoList = session.Advanced.LoadStartingWith<RavenJObject>("Raven/Versioning/", pageSize: 1024 );
foreach (var versioningInfo in versioningInfoList)
{
if (!versioningInfo.ContainsKey("Id"))
{
var fullInternalId = session.Advanced.GetDocumentId(versioningInfo);
var idSplitted = fullInternalId.Split('/');
var newId = idSplitted[idSplitted.Length - 1];
versioningInfo.Add("Id", newId);
}
}
session.SaveChanges();
}
}
}
Fix for re-indexing all the database:
private void ResetAllIndexes(string destinationRavenDbServer, string databaseName)
{
using (var documentStore = new DocumentStore { Url = destinationRavenDbServer, DefaultDatabase = databaseName })
{
documentStore.Initialize();
var indexes = documentStore.DatabaseCommands.GetIndexNames(0, 1024); // Update the 1024 first index, but you get the idea
foreach (var indexName in indexes)
{
documentStore.DatabaseCommands.ResetIndex(indexName);
}
}
}

Ravendb doesn't save propery Raven/Hilo/LoggingMessages

I have a problem saving an object to Ravendb.
Everytime i save the object into Ravendb ,
it only save this below
Raven/Hilo/LoggingMessages
{
"Max": 32
}
I don't even have property called Max on LoggingMessages class.
And, it kept doing that.
I used this Ravendb in a project that use NserviceBus.
My assumption is that the Ravendb Client library that is used by NserviceBus is different with other Ravendb Client.
Because I have no problem saving an object of type LoggingMessage in other project that doesn't have NserviceBus.
LoggingMessage errormessage = new LoggingMessage();
errormessage.MessageBody = "test";
errormessage.MessageId = "test";
using (var store = new DocumentStore { ConnectionStringName = "RavenDB" } )
{
store.Initialize();
using (var session = store.OpenSession())
{
session.Store(errormessage);
session.SaveChanges();
}
}
That's how RavenDB generates IDs. Its a system document. Don't worry about that.
What's probably happening is that you are saving this document to the database that NServiceBus is using, but you are looking at either the RavenDB System Database, or you are writing it to a separate one.
In Raven Studio, check the "databases" list in the upper-right corner.
In your code, you can set the database name either in the connection string, or as a parameter to the new DocumentStore constructor, or as a parameter to the OpenSession method.

RavenDb - How can I save changes to multiple document sessions in one transaction?

Within a single transaction scope, I am trying to save data to two separate Raven databases (on the same Raven server).
However, changes in the second session are not being saved to the server.
Here is the code I am using:
var documentStore = new DocumentStore { Url = "http://localhost:8081/" };
documentStore.Initialize();
documentStore.DatabaseCommands.EnsureDatabaseExists("database1");
documentStore.DatabaseCommands.EnsureDatabaseExists("database2");
using (var ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (var session1 = documentStore.OpenSession("database1"))
{
session1.Store(new Entity {Id = "1"});
session1.SaveChanges();
}
using (var session2 = documentStore.OpenSession("database2"))
{
session2.Store(new Entity {Id = "2"});
session2.SaveChanges();
}
ts.Complete();
}
I can see changes in session1 being saved to database1 but changes in session2 are not saved to database2. I've tried with RavenDb build 992 and build 2360
According to the Raven documentation, transactions across databases are supported.
How can I get changes from session2 to be committed?
The distributed transaction needs time to commit. You can either wait briefly with Thread.Sleep before checking your result, or you can set a special property in the session that is checking the result:
session.Advanced.AllowNonAuthoritativeInformation = false;
This seems like a bug, but it is actually by design. Read Working with System.Transactions in the RavenDB documentation.
(FYI - I didn't know this either until I checked.)