Try fast search NHibernate

19 November 2011

Azure queues: Producer

If you have read something about Azure’s queue you have probably seen some picture like this:

AzureQ_PC

A producer is anything (a class) that, in some moment, enqueue a message; more exactly this “anything” is something that take the role of message producer. For example it can be a MVC controller, more usually it can be an application-service or a domain-event but it can be even a view.

To simplify the work with messages, to our team, I have created two very simple classes on top of Microsoft.WindowsAzure.StorageClient. The main target of these two classes is establish some conventions and make the message strongly typed (it represent a limitation of the capability of Azure’s queues but for our works it is ok).

The basic

Giving a message like this:

public class NewsViewed
{
    public int CountryId { get; set; }
    public Guid NewsId { get; set; }
    public Uri Referrer { get; set; }
}

I would enqueue a new message with a line like this:

new MessageQueue<NewsViewed>().Enqueue(new NewsViewed
{
    CountryId = args.CountryId,
    NewsId = args.NewsId,
    Referrer = args.Referrer
});

When you want work with a message you will probably need some more information than the pure message data so a message in a queue is represented by:

public class QueueMessage<TMessage>
{
    public string Id { get; internal set; }
    public string PopReceipt { get; internal set; }
    public DateTime? InsertionTime { get; internal set; }
    public DateTime? ExpirationTime { get; internal set; }
    public DateTime? NextVisibleTime { get; internal set; }
    public int DequeueCount { get; internal set; }
    public TMessage Data { get; internal set; }
}

The conventions

The base convention is about the name of the queue which is the name of the class representing the message. For the example above the name of the queue is: newsviewed. The second convention is about the format of the message-content: ours Azure-queues will contains just strings, more exactly the JSON serialization of the class representing the message.

The MessageQueue implementation

Currently the max message size is 8KB, perhaps, hopefully NO, we will need more space so the MessageQueue<TMessage> class have to be extensible to allow a gzip/de-gzip of the content or it needs take the real content from a blob… so far it is far away of our needs and I hope we will never need it.

The implementation is:

/// <summary>
/// Generic base class for messages.
/// </summary>
/// <typeparam name="TMessage">The type of the message.</typeparam>
/// <remarks>
/// The <typeparamref name="TMessage"/> have to be JSON serializable.
/// </remarks>
public class MessageQueue<TMessage> where TMessage : class
{
    private const int MaxMessageBlockAllowedByAzure = 32;
    private readonly CloudQueueClient queueClient;
    private readonly string queueName = typeof (TMessage).Name.ToLowerInvariant();

    public MessageQueue() : this(AzureAccount.DefaultAccount()) {}

    public MessageQueue(CloudStorageAccount account)
    {
        if (account == null)
        {
            throw new ArgumentNullException("account");
        }
        queueClient = account.CreateCloudQueueClient();
    }

    public int ApproximateMessageCount
    {
        get
        {
            CloudQueue queueRef = queueClient.GetQueueReference(queueName);
            queueRef.RetrieveApproximateMessageCount();
            if (queueRef.ApproximateMessageCount.HasValue)
            {
                return queueRef.ApproximateMessageCount.Value;
            }
            return 0;
        }
    }

    public void Enqueue(TMessage messageContent)
    {
        if (messageContent == null)
        {
            throw new ArgumentNullException("messageContent");
        }
        CloudQueue queueRef = queueClient.GetQueueReference(queueName);
        var message = new CloudQueueMessage(SerializeObjectAsString(messageContent));
        queueRef.AddMessage(message);
    }

    public QueueMessage<TMessage> Dequeue()
    {
        CloudQueue queueRef = queueClient.GetQueueReference(queueName);
        CloudQueueMessage message = queueRef.GetMessage();
        return ConvertToQueueMessage(message);
    }

    public IEnumerable<QueueMessage<TMessage>> Dequeue(int messagesCount)
    {
        CloudQueue queueRef = queueClient.GetQueueReference(queueName);
        IEnumerable<CloudQueueMessage> messages = queueRef.GetMessages(messagesCount < MaxMessageBlockAllowedByAzure ? messagesCount : MaxMessageBlockAllowedByAzure);
        return messages.Select(x => ConvertToQueueMessage(x));
    }

    public QueueMessage<TMessage> Dequeue(TimeSpan timeout)
    {
        CloudQueue queueRef = queueClient.GetQueueReference(queueName);
        CloudQueueMessage message = queueRef.GetMessage(timeout);
        return ConvertToQueueMessage(message);
    }

    public IEnumerable<QueueMessage<TMessage>> Dequeue(int messagesCount, TimeSpan timeout)
    {
        CloudQueue queueRef = queueClient.GetQueueReference(queueName);
        IEnumerable<CloudQueueMessage> messages = queueRef.GetMessages(messagesCount < MaxMessageBlockAllowedByAzure ? messagesCount:MaxMessageBlockAllowedByAzure, timeout);
        return messages.Select(x => ConvertToQueueMessage(x));
    }

    public QueueMessage<TMessage> Peek()
    {
        CloudQueue queueRef = queueClient.GetQueueReference(queueName);
        CloudQueueMessage message = queueRef.PeekMessage();
        return ConvertToQueueMessage(message);
    }

    public IEnumerable<QueueMessage<TMessage>> Peek(int messagesCount)
    {
        CloudQueue queueRef = queueClient.GetQueueReference(queueName);
        IEnumerable<CloudQueueMessage> messages = queueRef.PeekMessages(messagesCount < MaxMessageBlockAllowedByAzure ? messagesCount : MaxMessageBlockAllowedByAzure);
        return messages.Select(x => ConvertToQueueMessage(x));
    }

    public void Remove(QueueMessage<TMessage> queueMessage)
    {
        if (queueMessage == null)
        {
            throw new ArgumentNullException("queueMessage");
        }
        CloudQueue queueRef = queueClient.GetQueueReference(queueName);
        queueRef.DeleteMessage(queueMessage.Id, queueMessage.PopReceipt);
    }

    public void Remove(IEnumerable<QueueMessage<TMessage>> queueMessages)
    {
        if (queueMessages == null)
        {
            throw new ArgumentNullException("queueMessages");
        }
        CloudQueue queueRef = queueClient.GetQueueReference(queueName);
        foreach (var queueMessage in queueMessages)
        {
            queueRef.DeleteMessage(queueMessage.Id, queueMessage.PopReceipt);
        }
    }

    protected virtual string SerializeObjectAsString(TMessage messageContent)
    {
        // a subclass can gzipr the message (GZipStream) where the serialized TMessage is > 8KB
        return JsonConvert.SerializeObject(messageContent);
    }

    protected virtual TMessage DeserializeObjectFromString(string messageContent)
    {
        // a subclass can de-gzip the message
        return JsonConvert.DeserializeObject<TMessage>(messageContent);
    }

    protected virtual QueueMessage<TMessage> ConvertToQueueMessage(CloudQueueMessage message)
    {
        if (message == null)
        {
            return null;
        }
        string messageContent = message.AsString;
        return new QueueMessage<TMessage>
               {
                   Id = message.Id,
                   PopReceipt = message.PopReceipt,
                   DequeueCount = message.DequeueCount,
                   InsertionTime = message.InsertionTime,
                   ExpirationTime = message.ExpirationTime,
                   NextVisibleTime = message.NextVisibleTime,
                   Data = DeserializeObjectFromString(messageContent)
               };
    }
}

as you can see it is basically a wrapper.

The AzureAccount class, present in the parameters-less constructor, is our static class to access all our storages accounts.

The JsonConverter is the class of the famous Newtonsoft.Json.

The more simple step is done, the next will be about the three parts of the consumer.

10 November 2011

MVC3 : set active menu by controller name

Just as a “nice to have” in the default templates of MVC.

In the default CSS of MVC3 you can find some styles never applied. One of those style is about the selected menu:

ul#menu li.selected a
{
    background-color: #fff;
    color: #000;
}

In the _Layout.cshtml would be nice to have something like this:

    <script type="text/javascript">
        $(document).ready(function () {
            var controlerName = '@(ViewContext.RouteData.GetRequiredString("controller"))'.toLowerCase();
            $('ul#menu li a')
                .removeClass('selected')
                .filter(function (index) {
                    return $(this).attr('href').toLowerCase().indexOf(controlerName) != -1;
                })
                .addClass('selected');
        });
    </script>
</body>
</html>

Obviously the script can be more sophisticated but, the above, can be a simple start point to avoid some questions.

29 October 2011

Azure Hispano

En estos dos años fue bastante dificil compartir experiencias o aclarar dudas desarrolando para Windows Azure Platform.
Con la ayuda de @guadacasuso, @nahog, @gabrielsz, Fernarndo Aramburu, @aeidelman, @AleBanzas entre otros (disculpen si no recuerdo todos los nombres/links) nació ayer un nuevo grupo de habla hispana para que sea mas facil para todos compartir experiencias, conocimiento y/o aclarar dudas.
Si están por empezar alguna aplicacción en Azure, ya tienen una o simplemente son curiosos de ver lo que pasa pueden subscribirse a: http://tech.groups.yahoo.com/group/azurehispano/
 

Bienvenidos a la nube!!

13 August 2011

Parse string as Razor template

For a special requirement at work (actually a mix with self requirement) I need to get a chunk of HTML content from a persistence-system. Taken as is, it does not appear a big challenge but analyzing the problem a little bit more deeper I saw that that the HTML chunk may contain variables, it may need a model… to be short it may be so complex as a MVC-PartialView.

To achieve the target quickly I tried to find something in the NET but without so much lucky. I have found a framework that seems to do the work @razorengine but, after a quick look at the code, I didn’t feel so enthusiast especially for the use we have to give to this new feature of our application (web application in Azure with something high traffic). hmm…. so ? what I can do ?

Personally I think that the MVC team in Microsoft is one of the best teams Microsoft ever had and I’m pretty sure there should be a way to parse a string using Razor without so much static classes… here we go with the Saturday proof of concept.

The code will talk by itself…

The VisualStudio solution

StringAsRazorSolution

The base class

The beating heart of Razor is inside System.Web.Razor but to use it you need a class without any special reference, just some “special” methods.

namespace YourCompany.DynamicContents
{
    public abstract class DynamicContentGeneratorBase
    {
        private StringBuilder buffer;
        protected DynamicContentGeneratorBase()
        {
            DynModel = new ExpandoObject();
        }

        /// <summary>
        /// This is just a custom property
        /// </summary>
        public dynamic DynModel { get; set; }

        /// <summary>
        /// This method is required and have to be exactly as declared here.
        /// </summary>
        public abstract void Execute();

        /// <summary>
        /// This method is required and can be public but have to have exactly the same signature
        /// </summary>
        protected void Write(object value)
        {
            WriteLiteral(value);
        }

        /// <summary>
        /// This method is required and can be public but have to have exactly the same signature
        /// </summary>
        protected void WriteLiteral(object value)
        {
            buffer.Append(value);
        }

        /// <summary>
        /// This method is just to have the rendered content without call Execute.
        /// </summary>
        /// <returns>The rendered content.</returns>
        public string GetContent()
        {
            buffer = new StringBuilder(1024);
            Execute();
            return buffer.ToString();
        }
    }
}

Surprised ? yes!!… that is all you need.

The concept

With the System.Web.Razor.RazorTemplateEngine you can generate the source-code of concrete classes inherited from your abstract DynamicContentGeneratorBase. The generated code will have the concrete implementation of the abstract method Execute with the calls to the methods Write and WriteLiteral as required by your string. In practice giving a simple string as "<b>Well done @DynModel.Who !!</b>" the implementation of Execute, generated by Razor, will look like:

public override void Execute()
{
    WriteLiteral("<b>Well done ");
    Write(DynModel.Who);
    WriteLiteral(" !!</b>");
}

To use the generated source you have to compile it in an assembly and create an instance of the concrete class.

Usage

  1. static void Main(string[] args)
  2. {
  3.     const string dynamicallyGeneratedClassName = "DynamicContentTemplate";
  4.     const string namespaceForDynamicClasses = "YourCompany";
  5.     const string dynamicClassFullName = namespaceForDynamicClasses + "." + dynamicallyGeneratedClassName;
  6.  
  7.     var language = new CSharpRazorCodeLanguage();
  8.     var host = new RazorEngineHost(language)
  9.                   {
  10.                                 DefaultBaseClass = typeof(DynamicContentGeneratorBase).FullName,
  11.                                 DefaultClassName = dynamicallyGeneratedClassName,
  12.                                 DefaultNamespace = namespaceForDynamicClasses,
  13.                   };
  14.     host.NamespaceImports.Add("System");
  15.     host.NamespaceImports.Add("System.Dynamic");
  16.     host.NamespaceImports.Add("System.Text");
  17.     var engine = new RazorTemplateEngine(host);
  18.         
  19.     var tr = new StringReader(GetStringFromSomewhere()); // here is where the string come in place
  20.     GeneratorResults razorTemplate = engine.GenerateCode(tr);
  21.  
  22.     var compiledAssembly = CreateCompiledAssemblyFor(razorTemplate.GeneratedCode);
  23.  
  24.     var templateInstance = (DynamicContentGeneratorBase)compiledAssembly.CreateInstance(dynamicClassFullName);
  25.  
  26.     templateInstance.DynModel.Who = "Fabio";
  27.         
  28.     Console.WriteLine(templateInstance.GetContent());
  29.     Console.ReadLine();
  30. }
  31.  
  32. private static Assembly CreateCompiledAssemblyFor(CodeCompileUnit unitToCompile)
  33. {
  34.     var compilerParameters = new CompilerParameters();
  35.     compilerParameters.ReferencedAssemblies.Add("System.dll");
  36.     compilerParameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
  37.     compilerParameters.ReferencedAssemblies.Add("System.Core.dll");
  38.     compilerParameters.ReferencedAssemblies.Add(typeof(DynamicContentGeneratorBase).Assembly.Location);
  39.     compilerParameters.GenerateInMemory = true;
  40.  
  41.     CompilerResults compilerResults = new CSharpCodeProvider().CompileAssemblyFromDom(compilerParameters, unitToCompile);
  42.     Assembly compiledAssembly = compilerResults.CompiledAssembly;
  43.     return compiledAssembly;
  44. }
  45.  
  46. private static string GetStringFromSomewhere()
  47. {
  48.     return "<b>Well done @DynModel.Who !!</b>";
  49. }

Form line 7 to 20 I’m generating the source of a concrete class called YourCompany.DynamicContentTemplate using the Razor template engine, then I’m compiling the source in an in-memory assembly, at line 24 I’m creating an instance of the YourCompany.DynamicContentTemplate, at line 25 I’m assigning a value to my DynamicModel and the result is:

StringAsRazorResult

Winking smile

06 August 2011

Azure storage initialization

This is the “self response” to the previous post.

When your role starts on Azure there are some tasks which runs synchronously and some tasks which runs asynchronously. For complex startups you can set the configuration of each custom tasks in your ServiceDefinition.csdef. If you don’t need special tasks to setup your VM you will end initializing your Azure-storage (blob containers, tables and queues) somewhere. Our problem was exactly: WHERE?

If you have a WebRole you have two places where you can initialize the storage:

  • the WebRole
  • the Application_Start of the HttpApplication (Global.asax.cs)

Which is the right one ? are they ambivalent ? If you read the documentation there is something that is clear to me :

The Application_Start method is called after the RoleEntryPoint.OnStart method finishes. The Application_End method is called before the RoleEntryPoint.OnStop method is called.

From the doc the right place is the OnStart.

If you use the  AppSetting to store your account information (as we do to switch between production and test account) you have something like this (or an equivalent):

 

public static class AzureAccount
{
    private static string dataconnectionstring = "AzureDataConnectionString";

    static AzureAccount()
    {
        CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
        {
            string value = ConfigurationManager.AppSettings[configName];
            if (RoleEnvironment.IsAvailable)
            {
                value = RoleEnvironment.GetConfigurationSettingValue(configName);
            }
            
            configSetter(value);
        });
    }

    public static CloudStorageAccount DefaultAccount()
    {
        return CloudStorageAccount.FromConfigurationSetting(dataconnectionstring);
    }
}

and the WebRole overriding the OnStart should be safe:

public class WebRole : RoleEntryPoint
{
    public override bool OnStart()
    {
        InitializeAzureStorage();

        return base.OnStart();
    }

and the initialization with something like this:

CloudStorageAccount account = AzureAccount.DefaultAccount();

// initialize the storage using the account

but it does not work always and if you look around the NET you will see various posts using Thread.Sleep here and there. The fact is that if you are using just the Web.Config, to store the AppSetting needed by the storage initialization, you don’t know exactly when it will be available ergo those Thread.Sleep may work sometimes but not always. To be sure that the AppSetting will be the correct, and overall you actually have the AzureDataConnectionString, you have to modify both ServiceDefinition.csdef and ServiceConfiguration.cscfg in this way:

ServiceDefinition

ServiceConfiguration

Note: you don’t have to remove the AzureDataConnectionString from your web.config… it is still useful to run the application as a web-application.

19 July 2011

Azure Storage initialization

More than a post about “how initialize the Azure storage” this is a “bottle to sea” to check if somebody else known a best-practice, a recommendation or whatever you call it.

In the past year we had experimented the very nice and useful exception starting our Web-Role… if you have an application on Azure I’m pretty sure you saw it too:

TheNiceAzureError

Very nice and informative, even better than some of our exceptions in NHibernate.

The matter is that at some point you need the CloudStorageAccount and, at some point, you have to initialize the storage. We thought that the better place to initialize the storage is the HttpApplication.Application_Start() but… error; then we have tried the WebRole class and again… error. With no lucky I have tried to find some guideline about where initialize the storage, then I have opted for a “lazy initialization” at the first time an action with the storage is required but, again… error!!

Today I tried a new solution and hopefully it is the final-cut to the story. Here is the code:

public override bool OnStart()
{
    // For information on handling configuration changes
    // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
    RoleEnvironment.Changing += RoleEnvironmentChanging;
    WaitForRoleAvailability();

    InitializeAzureStorage();

    return base.OnStart();
}

private static void WaitForRoleAvailability()
{
    bool accountAvailable = false;
    do
    {
        try
        {
            AzureAccount.DefaultAccount();
            accountAvailable = true;
        }
        catch (RoleEnvironmentException e)
        {
            Thread.Sleep(3000);
        }
    } while (!accountAvailable);
}

And for the initialization:

InitializeAzureStorage

Today the error is away from us… but I would know if you know something better.

17 July 2011

NHibernate: playing with mapping by code (2)

galletto-alla-mediterranea
In the previous post you saw a simple example about a way to use the new mapping-by-code of NHibernate 3.2.0.
The class-by-class mapping will be, probably, the most used way just because it is very similar to the XML mapping and the “feeling of loss of control” is near to zero (the quiet of sense).
If you want experiment more adrenaline you can try ConfORM but if you like just a little bit of more adrenaline you can use the NHibernate’s ConventionModelMapper.


Inside the ConventionModelMapper

To understand what really is the ConventionModelMapper let me show you a piece of its code:
public class ConventionModelMapper : ModelMapper
{
    public ConventionModelMapper()
        : base(new SimpleModelInspector())
    {
        AppendDefaultEvents();
    }
clear! no? The ConventionModelMapper is just a specialization of a ModelMapper where, instead the ExplicitlyDeclaredModel, we are injecting another implementation of IModelInspector. To “simplify” its usage, and obscure to you the real power of Dependency-Injection, the ConventionModelMapper exposes some methods as, for instance:
public void IsPersistentProperty(Func<MemberInfo, bool, bool> match)
What are those three parameters of the delegate ?
The name of the method is the question : is it a persistent property ?
The MemberInfo is the subject of the question. The bool parameter is an “help” to take a decision and it represent what was explicitly defined (we will see later where was defined). The last bool is the answer of the question.
What happen if we have a look to the implementation of the above method ?
public void IsPersistentProperty(Func<MemberInfo, bool, bool> match)
{
    SimpleModelInspector.IsPersistentProperty(match);
}
As you can see the implementation is completely passed to the SimpleModelInspector, nothing more than an “simplification” to allow you the usage of just one class.


ConventionModelMapper vs class-by-class mapping

This is not a matter. All these ways to perform the mapping-task, in NHibernate 3.2.0, are not one versus others because you can use all together. You can organize your mapping as you feel more confortable. There will be users who prefer explicit-class-by-class for the whole mapping; there will be users who prefer the usage of ConventionModelMapper and the method-based-mapping to specify convention-exceptions/overrides; there will be users who prefer the usage of ConventionModelMapper and the class-by-class as an organization of convention-exceptions/overrides; there will be users who implements their IModelInspector based on attributes; there will be users who implements their IModelInspector based on a custom DSL.


The new mapping

Taking the domain of the previous post, and some conventions already defined there, we can start from something like this:
  1. var mapper = new ConventionModelMapper();
  2.  
  3. mapper.BeforeMapClass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
  4. mapper.BeforeMapJoinedSubclass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
  5. mapper.BeforeMapUnionSubclass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
  6.  
  7. mapper.BeforeMapProperty += (mi, propertyPath, map) =>
  8. {
  9.     if (typeof(decimal).Equals(propertyPath.LocalMember.GetPropertyOrFieldType()))
  10.     {
  11.         map.Type(NHibernateUtil.Currency);
  12.     }
  13. };
  14.  
  15. mapper.BeforeMapBag += (mi, propPath, map) =>
  16. {
  17.     map.Cascade(Cascade.All.Include(Cascade.DeleteOrphans));
  18.     map.BatchSize(10);
  19. };
  20.  
  21. mapper.BeforeMapClass += (mi, type, map) =>
  22.     map.Id(idmap => idmap.Generator(Generators.HighLow,
  23.         gmap => gmap.Params(new
  24.         {
  25.             table = "NextHighVaues",
  26.             column = "NextHigh",
  27.             max_lo = 100,
  28.             where = string.Format("EntityName = '{0}'", type.Name.ToLowerInvariant())
  29.         })));
  30.  
  31. Func<Type, bool, bool> matchRootEntity = (type, wasDeclared)=> typeof(Entity).Equals(type.BaseType);
  32. var entities = Assembly.GetExecutingAssembly().GetExportedTypes()
  33.     .Where(t => typeof(Entity).IsAssignableFrom(t) && !typeof(Entity).Equals(t)).ToList();
  34. mapper.IsEntity((type, wasDeclared) => entities.Contains(type));
  35. mapper.IsRootEntity(matchRootEntity);
  36. HbmMapping domainMapping = mapper.CompileMappingFor(entities);
More then the starting point (line 1), where I’m using just the constructor of ConventionModelMapper, the difference, so far, is from line 31 to 36. Because I have completely removed any kind of explicit mapping (that “incomplete class-by-class mapping”) I have to inform the ConventionModelMapper about:
  1. given a System.Type how recognize if it is an entity or not (line 32,33,34)
  2. given a System.Type how recognize if it is a root-entity (the top class of a hierarchy); line 31,35
  3. which are the classes that the ConventionModelMapper have to map (line 32, 36)
Which is the advantage ? With the mapping of the previous post each time I’m adding a class to the domain I have to add its mapping; using this new mapping I can add a class to the domain without touch the mapping.
The mapping process is not completed because in the removed class-by-class mapping there was two specifications outside our required conventions: the Customer.TaxId as natural-id and the Order.EmissionDay as Date. To specify only these two convention-exceptions I can use the method-based-mapping in this way:
mapper.Class<Customer>(map => map.NaturalId(nm => nm.Property(c => c.TaxId)));
mapper.Class<Order>(map => map.Property(o=> o.EmissionDay, pm=> pm.Type(NHibernateUtil.Date)));
You can put the two lines in any place before call mapper.CompileMappingFor(entities).


The result

The integration is pretty the same:
  1. var configuration = new Configuration();
  2. configuration.DataBaseIntegration(c =>
  3. {
  4.     c.Dialect<MsSql2008Dialect>();
  5.     c.ConnectionString = @"Data Source=localhost\SQLEXPRESS;Initial Catalog=IntroNH;Integrated Security=True;Pooling=False";
  6.     c.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
  7.     c.SchemaAction = SchemaAutoAction.Create;
  8. });
  9. configuration.AddMapping(domainMapping);
  10. configuration.AddAuxiliaryDatabaseObject(CreateHighLowScript(Assembly.GetExecutingAssembly().GetExportedTypes().Where(t => matchRootEntity(t, false))));
The difference is just at line 10.
After build the session-factory we will have again

And the XML will be (please look it closer):
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                   namespace="PlayWithMappingByCode"
                   assembly="PlayWithMappingByCode"
                   xmlns="urn:nhibernate-mapping-2.2">
  <class name="Customer" table="customer">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'customer'</param>
      </generator>
    </id>
    <natural-id>
      <property name="TaxId" />
    </natural-id>
    <property name="CommercialName" />
    <bag name="Orders" cascade="all,delete-orphan" batch-size="10">
      <key column="Customer" />
      <one-to-many class="Order" />
    </bag>
  </class>
  <class name="Order" table="order">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'order'</param>
      </generator>
    </id>
    <many-to-one name="Customer" />
    <property name="EmissionDay" type="Date" />
    <bag name="Items" cascade="all,delete-orphan" batch-size="10">
      <key column="Order" />
      <one-to-many class="OrderItem" />
    </bag>
  </class>
  <class name="OrderItem" table="orderitem">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'orderitem'</param>
      </generator>
    </id>
    <many-to-one name="Order" />
    <property name="Product" />
    <property name="Price" type="Currency" />
  </class>
</hibernate-mapping>
The mapping is correct and it works but just for a “casualty”…

16 July 2011

NHibernate: playing with mapping by code

GallettiAllaBraceNHibernate 3.2.0GA is going to be released and, around the NET, there are various questions about how use its “sexy-mapping”… “sexy-mapping” is not a serious definition? well… I’m bored by zero-one definitions.

I think that the “problem” is that I have explicitly avoided to call something “best practice” writing  my examples (as I done with ConfORM) and the new mapping-by-code is very flexible and you have various ways to achieve your target.
In this example I’ll try to resume the answers to various questions.

This time nobody sent me a domain so the case is not real… it is a domain just for  the exercise.



The domain

public class Entity
{
    public virtual int Id { get; set; }
}
public class Customer : Entity
{
    public virtual string CommercialName { get; set; }
    public virtual string TaxId { get; set; }
    public virtual IEnumerable<Order> Orders { get; set; }
}
public class Order : Entity
{
    public virtual Customer Customer { get; set; }
    public virtual DateTime EmissionDay { get; set; }
    public virtual IEnumerable<OrderItem> Items { get; set; }
}
public class OrderItem : Entity
{
    public virtual Order Order { get; set; }
    public virtual string Product { get; set; }
    public virtual decimal Price { get; set; }
}


The incomplete class-by-class mapping

In our mapping-process we can start from various points depending on our knowledge of NHibernate, our knowledge of the domain, how much we known our conventions, how much we really known the relations between classes and so on. For this exercise I’ll start from a very incomplete class-by-class mapping as the follow:
public class EntityMapping<T> : ClassMapping<T> where T : Entity
{
    public EntityMapping()
    {
        Id(x => x.Id);
    }
}
public class CustomerMapping : EntityMapping<Customer>
{
    public CustomerMapping()
    {
        Property(x => x.CommercialName);
        NaturalId(map => map.Property(x => x.TaxId));
        Bag(x => x.Orders, map => map.Key(km => km.Column("CustomerId")));
    }
}
public class OrderMapping : EntityMapping<Order>
{
    public OrderMapping()
    {
        ManyToOne(x => x.Customer, map => map.Column("CustomerId"));
        Property(x => x.EmissionDay, map => map.Type(NHibernateUtil.Date));
        Bag(x => x.Items, map => map.Key(km => km.Column("OrderId")));
    }
}
public class OrderItemMapping : EntityMapping<OrderItem>
{
    public OrderItemMapping()
    {
        ManyToOne(x => x.Order, map => map.Column("OrderId"));
        Property(x => x.Product);
        Property(x => x.Price);
    }
}
If you have studied the mapping-by-code you know that you can define everything using class-by-class mapping but I want show you how little is the step between explicit-mapping and conventions/defaults-mapping.


The ModelMapper

In this exercise I’ll use the ModelMapper. The ModelMapper delegates some responsibilities to others classes. You can see all classes involved analyzing all ModelMapper constructors overloads. If you have a look at the most simple constructor you will find that the ModelMapper uses, by default, the class ExplicitlyDeclaredModel. The ExplicitlyDeclaredModel does not apply any special behavior other than what was explicitly declared or NHibernate’s convetions about table/columns names and types. Using class-by-class mapping the basic usage of the ModelMapper can look as:
var mapper = new ModelMapper();
mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes());
HbmMapping domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
yes!, that is all… then you have to add the domainMapping to the NHibernate’s configuration instance before BuildSessionFactory.


Applying tables-naming conventions over ModelMapper

The first convention required is : “All table names are lowercase”
Any kind of convention, customization have to be declared before get all mappings so we can do something like this:
var mapper = new ModelMapper();
mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes());

mapper.BeforeMapClass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
mapper.BeforeMapJoinedSubclass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
mapper.BeforeMapUnionSubclass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());

HbmMapping domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
As you can see you can add all conventions even after add all mappings to the ModelMapper.


Applying property-types “conventions” over ModelMapper

“All properties defined as decimal have to be mapped as currency”
mapper.BeforeMapProperty += (mi, propertyPath, map) =>
{
    if (typeof(decimal).Equals(propertyPath.LocalMember.GetPropertyOrFieldType()))
    {
        map.Type(NHibernateUtil.Currency);
    }
};

 

Applying collections “conventions” over ModelMapper

“All Bags are bidirectional-one-to-many and the batch size is 10”
mapper.BeforeMapBag += (mi, propPath, map) =>
{
    map.Cascade(Cascade.All.Include(Cascade.DeleteOrphans));
    map.BatchSize(10);
};
Is that enough to accomplish the target ? No, is not. We have defined only some attributes of the collections declared as Bag but we haven’t defined which is the relation between the collection ReflectedType and the collection-item-type. We can’t define the one-to-many relation using the ModelMapper because the responsibility to define/discover all relation is delegated to the IModelInspector injected to the ModelMapper instance (note that I wrote instance). Out-of-the-box you can find some implementations of IModelInspector but if you want continue maintaining most of things under your control and you want learn the new mapping-by-code step-by-step you can simply use a class inherited from the “”default”” ExplicitlyDeclaredModel. In this case the implementation can be simply:
public class MySimpleModelInspector: ExplicitlyDeclaredModel
{
    public override bool IsOneToMany(MemberInfo member)
    {
        if(IsBag(member))
        {
            return true;
        }
        return base.IsOneToMany(member);
    }
}
and its usage is:
var modelInspector = new MySimpleModelInspector();
var mapper = new ModelMapper(modelInspector);

 

Applying POID strategy “conventions” over ModelMapper

At this point of the mapping-process we have a working an ready-to-work mapping for our above model but, where not defined, the default POID strategy is “assigned”. In this exercise I want use the HighLow strategy (aka HiLo) but not the simple version; I want use the per-entity-High-Low strategy.
Knowing how we are giving the name of the table (we wrote it just few lines above) the mapping of the convention is:
mapper.BeforeMapClass += (mi, type, map) =>
    map.Id(idmap => idmap.Generator(Generators.HighLow,
        gmap => gmap.Params(new
        {
            table = "NextHighVaues",
            column = "NextHigh",
            max_lo = 100,
            where = string.Format("EntityName = '{0}'", type.Name.ToLowerInvariant())
        })));
Is it enough ? Yes! It is… mmm… perhaps it is enough but not for me. By default NHibernate will generates a table for HighLow but will not insert all records needed by per-entity-High-Low. What we need is a smart IAuxiliaryDatabaseObject… something simple as:
private static IAuxiliaryDatabaseObject CreateHighLowScript(IModelInspector inspector, IEnumerable<Type> entities)
{
    var script = new StringBuilder(3072);
    script.AppendLine("DELETE FROM NextHighVaues;");
    script.AppendLine("ALTER TABLE NextHighVaues ADD EntityName VARCHAR(128) NOT NULL;");
    script.AppendLine("CREATE NONCLUSTERED INDEX IdxNextHighVauesEntity ON NextHighVaues (EntityName ASC);");
    script.AppendLine("GO");
    foreach (var entity in entities.Where(x => inspector.IsRootEntity(x)))
    {
        script.AppendLine(string.Format("INSERT INTO [NextHighVaues] (EntityName, NextHigh) VALUES ('{0}',1);", entity.Name.ToLowerInvariant()));
    }
    return new SimpleAuxiliaryDatabaseObject(script.ToString(), null, new HashedSet<string> { typeof(MsSql2005Dialect).FullName, typeof(MsSql2008Dialect).FullName });
}

 

Conclusions

Even if we started from a bored declarative (and incomplete) class-by-class-mapping we have changed its behavior without touch the initial mapping. The last step of the exercise is the integration with NHibernate3.2.0 and it is:
var configuration = new Configuration();
configuration.DataBaseIntegration(c =>
{
    c.Dialect<MsSql2008Dialect>();
    c.ConnectionString = @"Data Source=localhost\SQLEXPRESS;Initial Catalog=IntroNH;Integrated Security=True;Pooling=False";
    c.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
    c.SchemaAction = SchemaAutoAction.Create;
});
configuration.AddMapping(domainMapping);
configuration.AddAuxiliaryDatabaseObject(CreateHighLowScript(modelInspector, Assembly.GetExecutingAssembly().GetExportedTypes()));

var factory = configuration.BuildSessionFactory();
// we are now ready to work with NHibernate
After build the session-factory in our db we will have:
PlatWithMappingByCode
For Tommaso guys (non crede finché non tocca)
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                   namespace="PlayWithMappingByCode"
                   assembly="PlayWithMappingByCode"
                   xmlns="urn:nhibernate-mapping-2.2">
  <class name="Customer" table="customer">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'customer'</param>
      </generator>
    </id>
    <natural-id>
      <property name="TaxId" />
    </natural-id>
    <property name="CommercialName" />
    <bag name="Orders" cascade="all,delete-orphan" batch-size="10">
      <key column="CustomerId" />
      <one-to-many class="Order" />
    </bag>
  </class>
  <class name="Order" table="order">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'order'</param>
      </generator>
    </id>
    <many-to-one name="Customer" column="CustomerId" />
    <property name="EmissionDay" type="Date" />
    <bag name="Items" cascade="all,delete-orphan" batch-size="10">
      <key column="OrderId" />
      <one-to-many class="OrderItem" />
    </bag>
  </class>
  <class name="OrderItem" table="orderitem">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'orderitem'</param>
      </generator>
    </id>
    <many-to-one name="Order" column="OrderId" />
    <property name="Product" />
    <property name="Price" type="Currency" />
  </class>
</hibernate-mapping>