• Making Sure A NHibernate IInterceptor Is In The Session

    Building on the previous post Intercepting NHibernate to Handle Additional Database Work, I used the ILifecycle interface to ensure the IInterceptor was setup on the session before saving MyEntity. I ILifecycle interface is deprecated, but I needed some way to make sure the interceptor was there. If an entity has the ILifecycle interface nothing more is needed, NHibernate will call the methods. I used the OnSave method, to inspect the session instance and throw and exception if needed. Anyway, here’s the code:

    public class MyEntity : ILifecycle
    {
        public virtual int Id { get; set; }
        public virtual int ParentId { get; set; }
      
        public virtual LifecycleVeto OnSave(ISession s)
        {
            var sessionDelegate = s as SessionDelegate;
            var session = sessionDelegate != null ? sessionDelegate.InnerSession as SessionImpl : s as SessionImpl;
      
            if (session != null && session.Interceptor.GetType().Equals(typeof(MyEntityInterceptor)))
                return LifecycleVeto.NoVeto;
      
            throw new ApplicationException("MyEntityInterceptor needs to be registered with the container.");
        }
      
        public virtual LifecycleVeto OnUpdate(ISession s)
        {
            return LifecycleVeto.NoVeto;
        }
      
        public virtual LifecycleVeto OnDelete(ISession s)
        {
            return LifecycleVeto.NoVeto;
        }
      
        public virtual void OnLoad(ISession s, object id)
        {
        }
    }
    

    I think there are potentially better ways to handle this, but with the existing constraints on the code and time work something out, this was the way I went.

  • Intercepting NHibernate to Handle Additional Database Work

    Today I needed to take addition database action when an entity is saved or deleted. A trigger might have been an option, but I try to limit the use of triggers. NHibernate to the rescue! Since the code was already using NHibernate it was an easy choice. There are a couple of options here. First is to use a stored procedure for the insert. However, that requires not using identity columns and wouldn’t work in this case. There is the ILifecycle interface, but it is deprecated and doesn’t have after-save hooks. Which leaves the IInterceptor interface.

    Sub-classing EmptyInterceptor, I overrode the needed methods. If the entity is the one I’m concerned with, I store it or it’s data for later use in a queue collection. In the PostFlush method the entities stored in the queue will have their Identity set and can be used to set the properties for the additional work. Also, the deleted object will have been deleted which is important. I’m not sure I needed lock the queue objects, but I guess there is a change the session could be used on multiple threads and to be save they are locked.

    The named queries are stored in the MyEntity Mapping file using the sql-query element.

    public class MyEntityInterceptor : EmptyInterceptor
    {
        private ISession session; 
        private readonly Queue<MyEntity> saves = new Queue<MyEntity>();
        private readonly Queue<int> deletes = new Queue<int>(); 
      
        public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, global::NHibernate.Type.IType[] types)
        {
            var myEntity = entity as MyEntity;
      
            if (myEntity != null)
                saves.Enqueue(myEntity);
      
            return true;
        }
      
        public override void OnDelete(object entity, object id, object[] state, string[] propertyNames, global::NHibernate.Type.IType[] types)
        {
            var myEntity = entity as MyEntity;
      
            if (myEntity != null)
                lock (deletes) 
                    if (!deletes.Contains(myEntity.ParentId))
                        deletes.Enqueue(myEntity.ParentId); 
        }
          
        public override void PostFlush(ICollection entities)
        {
            ExecuteSaves();
            ExecuteDeletes();
        }
          
        private void ExecuteSaves()
        {
            lock (saves) 
                while (saves.Count > 0) 
                    {
                        var myEntity = saves.Dequeue();
    
                        session.GetNamedQuery("SqlToExecuteForSaves") 
                            .SetInt32("Id", myEntity.Id)
                            .ExecuteUpdate();
                    }
        }
              
        private void ExecuteDeletes()
        {
            lock (deletes)
                while (deletes.Count > 0) 
                    {
                        var id = deletes.Dequeue();
    
                        session.GetNamedQuery("SqlToExecuteForDeletes") 
                            .SetInt32("Id", id)
                            .ExecuteUpdate();
                    }
            }
      
        public override void SetSession(ISession session)
        {
            session = session;
        }
    }
                  
    public class MyEntity
    {
        public int ParentId;
        public int Id;
    }
    

    Since it’s using the ISession and IQuery interface, unit testing was easy.

    The code is also using the NHibernateFacility from the CastleProject. Which makes adding interceptors as easy as adding them to the container. The naming is important as that’s how the facility looks up the interceptors. The first will be used for all session factories unless there is on for the specific factory as the second option shows.

      container.Register(Component.For<IInterceptor>()
          .ImplementedBy<MyEntityInterceptor>()
          .Named("nhibernate.session.interceptor"));
    
      container.Register(Component.For<IInterceptor>()
          .ImplementedBy<MyEntityInterceptor>()
          .Named("nhibernate.session.interceptor.MyOtherFactoryAlias"));
    
  • N2CMS Build From Source

    image

    1. Download source
    2. Run Prepare_Dependencies-vs2008.bat
    3. Deploy_Everything-vs2008.bat
    4. Copy the output/Templates_Mvc directory to a new directory for the projects
    5. Edit permissions on the wwwroot sub folder to add IIS_USERS if needed.
    6. x64 only: download SQLite and copy the x64 version of System.Data.SQLite.dll to wwwroot\bin
    7. Follow the instructions in the install.txt
  • FluentNHibernate Many-To-Many Mapping

    Explained here Hackingon.net: Many-to-Many Relationships With Fluent NHibernate Automapping

  • Automating Releases with SFTP

    I’m trying to automate the deployment process for a website. I’m using Psake for the build process and Migrator.Net for the db migrations. Which left the problem of getting the code to the server. I’ve taken a stab that this using this guide to setup SFTP with a restricted user with just SFTP access using public/private keys.

    Next was to automate the file upload, first I just used at batch file and psftp.exe, this worked except it re-uploads everything, much of which didn’t change. So, next was FileZilla, no luck there. Finally, WinSCP which works ok, but it doesn’t seem to allow a fully automated sync of files, but it does get close.

  • Asp.Net MVC CheckBoxList HtmlHelper Extension

    I added some more methods to the code provided by Tyler Garlick’s CheckBoxList for ASP.net MVC to allow a dictionary to be passed in place of a list of SelectListItems and an optional list of selected ids. Anyway, here’s the full class.

    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
      
    namespace System.Web.Mvc
    {
        public static class CheckBoxListHelper
        {
            public static string CheckBoxList(this HtmlHelper helper, string name, IDictionary<string, string> items)
            {
                return CheckBoxList(helper, name, items, null, null);
            }
      
            public static string CheckBoxList(this HtmlHelper helper, string name, IDictionary<string, string> items, IDictionary<string, object> checkboxHtmlAttributes)
            {
                return CheckBoxList(helper, name, items, null, checkboxHtmlAttributes);
            }
      
            public static string CheckBoxList(this HtmlHelper helper, string name, IDictionary<string, string> items, IEnumerable<string> selectedValues)
            {
                return CheckBoxList(helper, name, items, selectedValues, null);
            }
      
            public static string CheckBoxList(this HtmlHelper helper, string name, IDictionary<string, string> items, IEnumerable<string> selectedValues, IDictionary<string, object> checkboxHtmlAttributes)
            {
                var selectListItems = from i in items
                                      select new SelectListItem
                                                 {
                                                     Text = i.Key,
                                                     Value = i.Value,
                                                     Selected = (selectedValues != null && selectedValues.Contains(i.Value))
                                                 };
      
                return CheckBoxList(helper, name, selectListItems, checkboxHtmlAttributes);
            }
      
            public static string CheckBoxList(this HtmlHelper helper, string name, IEnumerable<SelectListItem> items)
            {
                return CheckBoxList(helper, name, items, null);
            }
      
            public static string CheckBoxList(this HtmlHelper helper, string name, IEnumerable<SelectListItem> items, IDictionary<string, object> checkboxHtmlAttributes)
            {
                var output = new StringBuilder();
      
                foreach (var item in items)
                {
                    output.Append(&ldquo;&ldquo;);
                    var checkboxList = new TagBuilder("input&rdquo;);
                    checkboxList.MergeAttribute(&ldquo;type&rdquo;, &ldquo;checkbox&rdquo;);
                    checkboxList.MergeAttribute(&ldquo;name&rdquo;, name);
                    checkboxList.MergeAttribute(&ldquo;value&rdquo;, item.Value);
      
                    // Check to see if it&rsquo;s checked
                    if (item.Selected)
                        checkboxList.MergeAttribute(&ldquo;checked&rdquo;, &ldquo;checked&rdquo;);
      
                    // Add any attributes
                    if (checkboxHtmlAttributes != null)
                        checkboxList.MergeAttributes(checkboxHtmlAttributes);
      
                    checkboxList.SetInnerText(item.Text);
                    output.Append(checkboxList.ToString(TagRenderMode.SelfClosing));
                    output.Append(&ldquo;  &rdquo; + item.Text + &ldquo;&rdquo;);
                }
      
                return output.ToString();
            }
        }
    }
    

    On the view you can pass a dictionary made from items in your view model and selected values form your view model.

    <div>
        ${Html.CheckBoxList(&ldquo;Product.Categories&rdquo;,
          ViewData.Model.Categories.ToDictionary(c => c.Name, c => c.Id.ToString()),
          ViewData.Model.Product.Categories.Select(c => c.Id.ToString()))}
    </div>
    

    In the controller you can access the form values in the request as a comma list of values by the name of the form field.

    Request.Form["Product.Categories"]
    

    Hope this helps and thanks to Tyler Garlick for meat of the code.

    [UPDATE] Tyler has updated is code for MVC 2.0, here.

  • Spark T4 Templates For S#arp Architecture

    Here’s a quick conversion of the Views to Spark views for the CurdScaffolding of S#arp Architecture V1. I’m still new to T4 and Spark, so they might need some adjustment, but they seem to work ok for a simple entities.

    SparkTT.zip