Querying on Child Count With NHibernate

10. July 2009

This is a recent question raised in NHibernate Users Group. The user wanted to realize the following query with Criteria api.

var result = db.Person.Where(x => x.Pets.Count > 0 && x.Alive)
.OrderBy(x => x.Name);

This is not a simple query, but it has a solution

DetachedCriteria crit = DetachedCriteria.For(typeof (Person), "p2")
    .CreateCriteria("p2.Pets","Pets")
    .Add(Restrictions.EqProperty("p.Id", "p2.Id"))
    .SetProjection(Projections.Count("Pets.Id"));

ICriteria c = s.CreateCriteria(typeof (Person), "p")
    .Add(Restrictions.Gt(Projections.SubQuery(crit), 0))
    .Add(Restrictions.Eq("p.Alive",true))
    .AddOrder(Order.Asc("p.Name"));

What we had to do is to create a DetachedCriteria and on that execute CreateCriteria so that we can do querying on our collection.

The other way is simpler, but requires you to use HQL (below query is provided by Fabio Maulo)

session.CreateQuery("from Person p where  size(p.Pets) > 0 and p.Visible = true order by p.Name")

or

session.CreateQuery("from Person p where  p.Pets.size > 0 and p.Visible = true order by p.Name")

 

I hope this helps.

Castle NHibernate Facility – Configuration

7. April 2009

Castle’s extensibility points provide you many ways to make your life easier. One and most widely used extensibility point is the facilities. By using facilities, you can integrate various other frameworks and technologies easily.

I am going to talk about NHibernate Integration Facility, which is currently lead by me. It was originally written by Hamilton Verissimo, and its current shape is more or less the same as what he wrote.

The purpose of this post is to get feedback and shape the documentation accordingly.

Now, after an historical introduction, lets talk about the facility’s purpose, and in as the first part of the documentation, the configuration.

The purpose
The purpose of this facility to provide an easy way to integrate NHibernate into MicroKernel backed applications. The facility provides a nice way to manage multiple session factories, a good way to manage sessions and it also provides some other structures that can be used to further integrate other frameworks such as Fluent NHibernate. It also plays nicely with other Castle services such as Transaction Management.


The Configuration
Currently, the facility can only be configured via XML, but it provides some extension points that can be used to configure it programmatically. The traditional way of configuring it is as given below. 

<configuration>
    <facilities>
        <facility
          id="nhibernatefacility"
          type="Castle.Facilities.NHibernateIntegration.NHibernateFacility, Castle.Facilities.NHibernateIntegration"
          [optional: configurationBuilder="Your custom configuration builder"] [optional: isWeb="Your custom configuration builder"]>
            <factory id="sessionFactory1">
                <settings>
                    <item key="connection.provider">NHibernate.Connection.DriverConnectionProvider</item>
                    <item key="connection.driver_class">NHibernate.Driver.SqlClientDriver</item>
                    <item key="connection.connection_string">Data Source=.;Initial Catalog=test;Integrated Security=SSPI</item>
                    <item key="dialect">NHibernate.Dialect.MsSql2000Dialect</item>
                    <item key="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</item>
                </settings>
                <assemblies>
                    <assembly>YourAssembly.Name.Here</assembly>
                </assemblies>
            </factory>
        </facility>
    </facilities>
</configuration>
<httpModules>
    <add name="NHibernateSessionWebModule"
             type="Castle.Facilities.NHibernateIntegration.Components.SessionWebModule, Castle.Facilities.NHibernateIntegration"/>
</httpModules>

isWeb: In case of web application, you should set this to true, implement IContainerAccessor in your HttpApplication (the global.asax) also add following lines to your <httpModules> section


As it can bee seen here, it is not very much different from the way we configure NHibernate. What happens behind the scenes are that: Facility creates an NHibernate Configuration, registers the SessionManager, and make those ready to be resolved.

The facility provides you some way to modify the Configuration that is created behind the scenes. The point is called IConfigurationContributor. By implementing classes that derive from that interface and registering them to container, you’ll be able to modify the NHibernate Configuration, just before the SessionFactory is resolved. The interface is simple

public interface IConfigurationContributor
{
    void Process(string name,Configuration config);
}

 

The name corresponds to the id in the configuration.

You can also Configure NHibernate Configuration via the IConfigurationBuilder interface. Currently, there are 2 built in ConfigurationBuilders, namely DefaultConfigurationBuilder and XmlConfigurationBuilder.
The default one is the one that parses the thing you see above while XmlConfigurationBuilder uses NH’s native xmls.

In the next post, I will hopefully show to integrate FluentNHibernate using custom ConfigurationBuilder

, ,

NHibernate POID Generators revealed

20. March 2009

(Disclaimer: This post will be more or less a paraphrase of Fabio Maulo’s post, and I hope I can improve it a bit)

This topic is something that I wanted to write because I wasn’t aware of the drawbacks of “ native/identityimage” generator has until Fabio told me. Now it is my turn to spread the information to those who aren’t aware too. I even made a small poll via twitter, to see who uses what, and the result turns out to be that majority of people use identity/native for some reasons.

NHibernate has several object identifier generators for entities. Each of them has their cons and pros as anything else does.

We can basically seperate generators into two: PostInsertGenerator and ORM Style generators ( you can also call them identity style vs orm stlye generators). impact on your  I will investigate them in their categories.

ORM Style Generators 

ORM style generator can generate the identifiers before objects are sent to database. This is advantageous because you don’t need to go to database in order to have the ID, then set a relation based on this id. It also promotes Unit-Of-Work since you don’t need to go to database everytime an object is added/updated instead you do those at the moment of commit. Those generators are what WE SUGGEST.

Currently NHibernate provides several ORM style generators, some of them are listed below.

  • Guid
    Generates id’s by calling Guid.NewGuid(). Main drawback of this is with indexes. We know that Guids are more or less random(or pseudo-random let’s say) and this randomness creates fragmentation in database index. If you also think that the field is a PK, then it becomes more dramatic since they are stored in sorted manner.
  • Guid.Comb
    A very clever improvement over the Guid way. It creates guid based on the system time, and the guid it creates is database friendly. It doesn’t cause fragmentation in the table. You can see it from here

    I wonder if anybody reads the ALT of images? 
    (Image taken from Pamir Erdem’s blog)
    The effect of SequentialNewId() for default value has more or less the same effect of Guid.Comb
  • HiLo/Sequence HiLo
    This one is the one I like the most. It is both index friendly and user friendly. A HiLo id has 2 parts as the name suggests they are Hi and Lo. Each session factory gets the Hi value from database (with locking enabled), and lo values are managed by the session factory on its own. This algorithm also scales really well. All factories gets the Hi value only once. This reduces the the database traffic that aims to get the Hi values.

Post Insert Generators / Identity Style Generators

Post insert generators, as the name suggest, assigns the id’s after the entity is stored in the database. A select statement is executed against database. They have many drawbacks, and in my opinion they must be used only on brownfield projects. Those generators are what WE DO NOT SUGGEST as NH Team.

Some of the drawbacks are the following

  1. Unit Of Work is broken with the use of those strategies. It doesn’t matter if you’re using FlushMode.Commit, each Save results in an insert statement against DB. As a best practice, we should defer insertions to the commit, but using a post insert generator makes it commit on save (which is what UoW doesn’t do).
  2. Those strategies nullify batcher, you can’t take the advantage of sending multiple queries at once(as it must go to database at the time of Save)

There are several Post Insert Generator strategies (hey 2.1 has even more!) some of which are listed below(there are many, check Fabio’s post here)

  1. Identity
    Identity generator uses the value that is generated by MsSQL "identity” stuff. However, it’s meaning in the mapping changes depending on the dialect. For example, if database supports MsSQL like identity, then it will be used, if it supports sequences, then sequences will be used, etc. Something I learnt today from the MSSQL group is that MSSQL may sometimes return invalid SCOPE_IDENTITY() value.
  2. Guid.Native
    If I am to speak in terms of MsSQL terminology, it uses the NEWID() function to get a uniqueidentifier.

Comparison

I hear you say “you speak too much, all those doesn’t tell much, show me the code!” There it is, the comparison of post insert generators vs ORM style generators.

I will first start with demonstrating how they break UoW, then continue with Batcher! (did you know that NH uses NonBatchingBatcher by default? ;) )

The code under test is simple

[Test]
public void Should_not_insert_entity_in_a_transaction_HiLo()
{
    var post = new PostWithHiLo {Title = "Identity Generators Revealed"};
    var postComment = new PostCommentWithHiLo { Post = post, Comment = "Comment" };
    using (ISession session = factory.OpenSession())
    using (var tran = session.BeginTransaction())
    {
        session.Save(post); //No commit here
        session.Save(postComment);
        long insertCount = factory.Statistics.EntityInsertCount;
        Assert.That(insertCount, Is.EqualTo(0), "Shouldn't insert entity in a transaction before commit.");
    }
}

[Test]
public void Should_not_insert_entity_in_a_transaction_Identity()
{
    var post = new PostWithIdentity {Title = "Identity Generators Revealed"};
    var postComment = new PostCommentWithIdentity {Post = post, Comment = "Comment"};
    using (ISession session = factory.OpenSession())
    using (var tran = session.BeginTransaction())
    {
        session.Save(post);
        session.Save(postComment);
        long insertCount = factory.Statistics.EntityInsertCount;
        Assert.That(insertCount, Is.EqualTo(0), "Shouldn't insert entity in a transaction before commit.");
    }
}

Now, let’s try it. What do you expect in both cases? Should both test pass? The test with identity strategy fails as it tries to insert the entity even before calling a commit.

Now here is the explanation for the batcher:

using (ISession session = factory.OpenSession())
using (var tran = session.BeginTransaction())
{
    for (int i = 0; i < 3; i++)
    {
        var post = new PostWithHiLo {Title = string.Format("Identity Generators Revealed {0}", i)};
        session.Save(post);
    }
    tran.Commit();
}

The upper code sends queries to database only once. However, if you’re using the Identity style generators, then you’re in trouble.

Conclusion

You should know what you’re gaining and what you’re losing when using an identifier strategies. In case of a greenfield application, my choice would be to use HiLo as it is more user friendly(and this is what NH team suggests actually), and Guid.Comb in case a replication kinda thing is required. Most probably I wouldn’t use Identity. However, on a brownfield application, where you can’t really change the DB schema for some reason, than Identity should be used as a last resort.

I’d like to end this post with two sayings that I hear/see from Fabio

Human knowledge belongs to the world!
Quality is not achieved by chance!

An improvement on SessionFactory Initialization

14. March 2009

UPDATE: I have just committed the PersistentConfigurationBuilder for Castle NHibernate Facility. Thank you Jonathon Rossi for informing me!

We have received several complaints about slowness of SessionFactory initialization when there’s hundreds of entities, and Ayende has replied one of them here. It even gets worse if you’re using it in a web environment. You may think that it is not a problem since SessionFactory is initialized once in a web environment, but the major impact is not on production but development. Think how many times you start your application a day.

The problem is not really with NHibernate but with xml validation against the schema. Here are some profiler results for SessionFactory initialization with one thousand entities:

image

As you see, the adding XML resources takes the most time and the reason behind this is the schema validation. There is also an I/O cost involved (1040 resources should be read by NHibernate). There are several ways to get rid of it, one being the serialization of configuration. I spend 3 days (statics prevented me from spotting some bugs in the code) on this and I believe it pretty much works for every configuration. Another way of doing this is the merging of HBM files, which I believe faster than Serialization as Deserialization also takes some amount.

Now the results for the one using the Deserialized Configuration.

image

A nice feature of dotTrace allows us to compare the performance improvements over the old way.

image

We got 10 seconds rescued! Yay!

Now I am going to show how I used this feature in Castle NHibernate Facility. We have IConfigurationBuilder that is used to integrate various Configuration sources (such as FluentNHibernate).

First of all I must ensure that if any of the files that are used to create the Configuration change, we shouldn’t use the serialized configuration, instead the Configuration should be re-created.

public override Configuration GetConfiguration(IConfiguration config)
{
    log.Debug("Building the Configuration");

    string fileName = config.Attributes["fileName"];

    IConfiguration dependsOn = config.Children["dependsOn"];
    IList<string> list = new List<string>();

    foreach (var on in dependsOn.Children)
        list.Add(on.Value);

    Configuration cfg;
    if (IsNewConfigurationRequired(fileName, list))
    {
        log.Debug("Configuration is either old or some of the dependencies have changed");
        using(var fileStream = new FileStream(fileName, FileMode.OpenOrCreate))
        {
            cfg = base.GetConfiguration(config);
            this.WriteConfigurationToStream(fileStream, cfg);
        }
    }
    else
    {
        using (var fileStream = new FileStream(fileName, FileMode.OpenOrCreate))
        {
            cfg = this.GetConfigurationFromStream(fileStream);
        }
    }
    return cfg;
}protected virtual bool IsNewConfigurationRequired(string fileName,IList<string> dependencies)
{
    if (!File.Exists(fileName))
        return true;
    FileInfo fi = new FileInfo(fileName);
    DateTime lastModified = fi.LastWriteTime;
    bool requiresNew=false;
    for (int i = 0; i < dependencies.Count && !requiresNew; i++)
    {
        FileInfo dependency = new FileInfo(dependencies[i]);
        DateTime dependencyLastModified = dependency.LastWriteTime;
        requiresNew |= dependencyLastModified > lastModified;
    }
    return requiresNew;
}

Code doesn’t look really good, I guess, so I am open to any suggestions on improvement. The code is not yet in Castle Codebase, as our NH dependency on trunk is not the latest (and i am too lazy to update it). When I find time, I may update the dependency if others agree.

There is one thing that you have to be careful about. You must be aware that if you’re using IUserType, IInterceptor, ISqlFunction etc, all of those should be Serializable too!

, ,

Debugging NH itself with NHProf

3. March 2009

This is my second chance to play with NHProf, first was for demonstration purposes to my friend Murat Haksal. As we are close to release in NH, and being lazy for about a month and a half, I decided to do some work on NH (including serialization of configuration).

As usual, I first looked JIRA for some issues I can solve. I found NH-1391 important, so decided to give it a try. I created the test case and it was failing for lazy and non-lazy collections. This is obviously a bug, however it wasn’t that easy to debug. The reason for being hard is that debugger does many things behind the scenes, and it may even initialize your collections. Therefore, I wasn’t able to locate/trace the problem ( I usually forget where collection queries are built and executed, even if I spent some time before for other bugs). At this time, NH Prof came to the rescue.

By default, it doesn’t show StackTrace that belongs to NHibernate,Castle, etc. However, you can tell it not to do so.

 twitter
I removed the namespace NHibernate in order to be able to see the stack trace that belongs to NHibernate.

 


Then the problem was crystal clear. CollectionLoader class is responsible for collections. The rest was easy.

Thanks Ayende! You made it easy!

,

Contributing to OSS – Creating a test case & patch

15. December 2008

For some time from now, I have been _trying_ to contribute some opensource projects including NHibernate, Castle(even though i couldn’t contribute the latter yet). People are trying to help the projects by creating issues in the issue trackers. The thing we come face to face usually is that the information provided in the issues are not enough to reproduce, or too time consuming to write a test for(e.g. NHibernate tests usually needs 3 files, 1 for test fixture, 1 for mappings and 1 for the entity). This issue prevents developers from fixing the issue very quickly.

In this post, I will try to explain how to write a test for NHibernate codebase, but the idea is the same for all projects.

There was already a really good article in NHForgegoing over the same steps I am going to follow, but I want people get used to OSS world, hence Source Code Management

Getting the source code

You need to have an SVN client, and during this article I will use Tortoise SVN directly (there are some other clients namely VisualSVNand  AnkhSVN (free)built on top of Tortoise SVN).

  1. In order to get the source code, you should create a folder named nhibernate wherever you want.
  2. Right-click the folder, and press SVN Checkout
  3. Enter the URL of repository(https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/ for nhibernate) and imagepress OK to check out the code.  
  4. Luckily, I was able to get the code in one trip, but this is not always the case. Connection may get broken, or sourceforge may kill you during the checkout. If this is the case, right click the folder and click on Update

    image  
  5. Open a command window in that folder, go to nhibernate subfolder and type nant. This action not only builds the sourcecode, but also generate AssemblyInfo.cs which is required for you to build solution in VS.

    image 
  6. Now you are ready to open solution in visual studio. Go ahead and double-click on .sln file.

    image

    Ups wtf is that? Due to some custom build steps nhibernate is using, visual studio warns us. Uncheck the box below and click on Load project normally. Then press ok.

Creating the test case

The best way to illustrate a bug is a test case. I am probably the last person to talk on how a unit test should be and there are already some good articles on what to do / or better what not to do on the web, but i want to illustrate some points that I think important.

  1. Isolation
    A test case should be isolated from every other non-relevant  component. I see several times that people are creating tests with other projects dll’s. This can be really hard for us to isolate. NHibernate tests shouldn’t have any other dependency other then NHibernate itself.
  2. Short test cases
    It may not be easy to find where the bug is when we have tens of lines in a test. This idea is related to isolation in someway and should be taken into account.
  3. Verify results
    There are times when I see a test code that doesn’t check for the results, but only checks if it doesn’t throw exception. This is plain wrong! A code may not throw an exception, but still not produce the correct result. Please take care with this issue.

I know, I talked a lot, and now it is code time!

  1. First thing you should do is to create a test folder named NHXXXX in NHibernate.Test/NHSpecificTest. Tests that are related to bugs go into NHSpecificTest for tracking purposes.
  2. Second thing is to create entities. (Assuming that you’ll need to demonstrate it using a session and you’ll query the database, otherwise you can skip this step and the following).
    public class MyClass
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }
  3. Now it comes to mappings. The thing you must be aware of is that if you give “Mappings.hbm.xml”, NHibernate will automagically catches it.
    <?xml version="1.0" encoding="utf-8"?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                       assembly="NHibernate.Test"
                       namespace="NHibernate.Test.NHSpecificTest.NH1552">
    
        <class name="MyClass">
            <id name="Id">
                <generator class="native"/>
            </id>
            <property name="Name"/>
        </class>
    </hibernate-mapping>
  4. Now we should create the test case. Our test case should inherit from NHibernate.Test.NHSpecificTest.BugTestCase to make the things easier.

    If our test is specific to a dialect, we should override virtual bool AppliesTo(Dialect dialect) method, and for this blogpost we’ll use issue NH-1552which is specific to MsSql2005Dialect
    protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect)
    {
        return dialect is MsSql2005Dialect;
    }

  5. There are some predefined methods for the test case such as OnSetup() and OnTearDown(). In OnSetUp() method, you initialize the data and on TearDown() you generally only remove the data. For our purpose, since we check if paging works with SqlQuery, we need at least 3 items.
    protected override void OnSetUp()
    {
        using (var session = this.OpenSession())
        {
            using (var tran = session.BeginTransaction())
            {
                MyClass newServ = new MyClass();
                newServ.Name = "tuna";
                MyClass newServ2 = new MyClass();
                newServ2.Name = "sidar";
                MyClass newServ3 = new MyClass();
                newServ3.Name = "berker";
                session.Save(newServ);
                session.Save(newServ2);
                session.Save(newServ3);
                tran.Commit();
            }
        }
    }

  6. Now we write the TearDown() to remove the data. 
    protected override void OnTearDown()
    {
        using (var session = this.OpenSession())
        {
            using (var tran = session.BeginTransaction())
            {
                session.Delete("from MyClass");
                tran.Commit();
            }
        }
    }

  7. Now we need to write 3 test cases for paging, one with FirstResult, one with MaxResult, and one with both.  
     
    I have to admit that _works_as_expected_ doesn’t mean much, but that’s the way i like it.
    [Test]
    public void Paging_with_sql_works_as_expected_with_FirstResult()
    {
        using (var session = this.OpenSession())
        {
            using (var tran = session.BeginTransaction())
            {
                string sql = "select * from MyClass order by Name asc";
                IList<MyClass> list = session.CreateSQLQuery(sql)
                    .AddEntity(typeof(MyClass))
                    .SetFirstResult(1)
                    .List<MyClass>();
                Assert.That(list.Count, Is.EqualTo(2));
                Assert.That(list[0].Name, Is.EqualTo("sidar"));
                Assert.That(list[1].Name, Is.EqualTo("tuna"));
            }
        }
    }
    
    [Test]
    public void Paging_with_sql_works_as_expected_with_MaxResult()
    {
        using (var session = this.OpenSession())
        {
            using (var tran = session.BeginTransaction())
            {
                string sql = "select * from MyClass order by Name asc";
                IList<MyClass> list = session.CreateSQLQuery(sql)
                    .AddEntity(typeof(MyClass))
                    .SetMaxResults(2)
                    .List<MyClass>();
                Assert.That(list.Count, Is.EqualTo(2));
                Assert.That(list[0].Name, Is.EqualTo("berker"));
                Assert.That(list[1].Name, Is.EqualTo("sidar"));
            }
        }
    }
    
    
    [Test]
    public void Paging_with_sql_works_as_expected_with_FirstResultMaxResult()
    {
        using (var session = this.OpenSession())
        {
            using (var tran = session.BeginTransaction())
            {
                string sql = "select * from MyClass";
                IList<MyClass> list = session.CreateSQLQuery(sql)
                    .AddEntity(typeof(MyClass))
                    .SetFirstResult(1)
                    .SetMaxResults(1)
                    .List<MyClass>();
                Assert.That(list.Count, Is.EqualTo(1));
                Assert.That(list[0].Name, Is.EqualTo("sidar"));
            }
        }
    }


  8. Now make sure that the tests are failing(now they all pass after we apply patch from Dana)

    image
    Now it is failing, btw, the image is from Resharper, which is a joy to use but you can also use NUnit
  9. If you can fix the bug, go ahead and fix it, if not it’s still fine. Jump to create a patch section

     

    Creating a Patch

    image 
    Creating a patch produces a diff for modified code pieces. When you click on Create Patch, you will probably see a bunch of files in the list, please make sure you only choose the ones you have added.


    image

    That’s it, take this patch file and send it to JIRA

    kick it on DotNetKicks.com

, , , ,

NHibernate hbm2ddl

23. November 2008

NHibernate has a number of configuration options: Enabling statistics, Caching etc. You can check more from here

I will now talk about an unknown feature(well, at least I didn’t know until I implement SchemaValidator): hbm2ddl.auto

Hbm2ddl.auto is declarative way to use SchemaExport / SchemaUpdate / SchemaValidator (well the latter sounds odd, maybe it would be better to call it SchemaValidate, what do you think?). If you add

<property name="hbm2ddl.auto">create</property>

for example, it will run

new SchemaExport(cfg).Create(false, true);

during SessionFactory initialization, with which you probably are familiar.

There are several options for hbm2ddl.auto.

  1. update executes SchemaUpdate which will modify your existing table with new mapping, without dropping any columns.
  2. create-drop executes SchemaExport when SessionFactory initializes and drops the schema at the end of the life of the factory.
  3. validate executes SchemaValidator which I blogged about here

If you prefer not to use programatic way, configuration is just here.

kick it on DotNetKicks.com

NHibernate SchemaValidator

23. November 2008

NHibernate provides a number of tools for developers to manage their database. I prefer mapping driven approach in which I let NHibernate generate the schema for database for me. By that way, I only concentrate on my domain. For me, database is not the center but only a tool for storage most of the cases.

This approach is valid only for greenfield projects. If you’re using a legacy database, however, things get more complicated and you write your mappings according to your database.

NHibernate now(with revision 3918, which means you have to use trunk until we release it) provides a way to verify your mappings against your database.

The usage is similar to other tools

I won’t write a dedicated code for this but rather I am going to copy the tests from the code itself.

[TestFixture]
public class SchemaValidateFixture
{
    [Test]
    public void ShouldVerifySameTable()
    {
        string resource1 = "NHibernate.Test.Tools.hbm2ddl.SchemaValidator.1_Version.hbm.xml";
        Configuration v1cfg = TestConfigurationHelper.GetDefaultConfiguration();
        using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource1))
        new NHibernate.Tool.hbm2ddl.SchemaExport(v1cfg).Execute(true,true,false,true);

        var v1schemaValidator = new NHibernate.Tool.hbm2ddl.SchemaValidator((v1cfg));
        v1schemaValidator.Validate();
    }
    [Test]
    public void ShouldNotVerifyModifiedTable()
    {
        string resource1 = "NHibernate.Test.Tools.hbm2ddl.SchemaValidator.1_Version.hbm.xml";
        string resource2 = "NHibernate.Test.Tools.hbm2ddl.SchemaValidator.2_Version.hbm.xml";
        Configuration v1cfg = TestConfigurationHelper.GetDefaultConfiguration();
        Configuration v2cfg = TestConfigurationHelper.GetDefaultConfiguration();
        using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource1))
            v1cfg.AddInputStream(stream);
        using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource2))
            v2cfg.AddInputStream(stream);
        new NHibernate.Tool.hbm2ddl.SchemaExport(v1cfg).Execute(true, true, false, true);
        var v2schemaValidator = new NHibernate.Tool.hbm2ddl.SchemaValidator((v2cfg));
        try
        {
            v2schemaValidator.Validate();                
        }
        catch (HibernateException e)
        {
            Assert.That(e.Message, Text.StartsWith("Missing column: Name"));
        }
    }
}

SchemaValidator has a single method called Validate. You give it the configuration and it validates the schema.

That’s it. In the next post I’ll write about an unknown configuration option for NHibernate.

kick it on DotNetKicks.com