ASP.NET Web Forms Extensibility: Model Binding Value Providers

ASP.NET 4.5 introduced model binding: basically, it is a way for databound controls – Repeater, GridView, ListView, etc – to be fed, not from a datasource control – ObjectDataSource, EntityDataSource, SqlDataSource, etc -, but from a method in the page. This method needs to return a collection, and may have parameters. The problem is: how these parameters get their values? The answer is: through a model binding value provider.

A model binding value provider is a class that implements IValueProvider, and normally is injected through a ValueProviderSourceAttribute-derived attribute. ASP.NET includes some implementations:

If we want, say, to return a value from the Common Service Locator, it’s pretty easy. First, an attribute:

[Serializable]

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]

public sealed class ServiceLocatorAttribute : ValueProviderSourceAttribute

{

    private readonly Type serviceType;

    private readonly String key;


    public ServiceLocatorAttribute(Type serviceType, String key = null)

    {

        this.serviceType = serviceType;

        this.key = key;

    }


    public override IValueProvider GetValueProvider(ModelBindingExecutionContext modelBindingExecutionContext)

    {

        return new ServiceLocatorValueProvider(this.serviceType, this.key);

    }

}

And now the actual value provider:

public sealed class ServiceLocatorValueProvider : IValueProvider

{

    private readonly Type serviceType;

    private readonly String key;


    public ServiceLocatorValueProvider(Type serviceType, String key)

    {

        this.serviceType = serviceType;

        this.key = key;

    }


    public Boolean ContainsPrefix(String prefix)

    {

        return true;

    }


    public ValueProviderResult GetValue(String key)

    {

        return new ValueProviderResult(ServiceLocator.Current.GetInstance(this.serviceType, this.key), null, CultureInfo.CurrentCulture);

    }

}

You can even have the ServiceLocatorAttribute implement the IValueProvider interface, I just separated it because conceptually they are different things.

Finally, here’s how we would use it:

public IQueryable<SomeEntity> GetItems([ServiceLocator(typeof(MyComponent), "SomeKey")] MyComponent cmp)

{

    //do something

}

Pretty sleek, don’t you think? Winking smile

Entity Framework Extensibility Index

Updated on March 10th.

Here you will find a list of all my posts on Entity Framework extensibility.

Freetext Extension in Entity Framework Code First

I posted before a solution for adding custom SQL functions to Entity Framework Code First as extension methods. This time I am going to show how we can do something similar for the FREETEXT function of SQL Server. Please note that this example will only work if you have the Fulltext Search component installed and your table is indexed.

OK, so we want to have an extension method like this:

[DbFunction("CodeFirstDatabaseSchema", "FREETEXT")]

public static Boolean Freetext(this String column, String value)

{

    return column.Contains(value);

}

In order for Entity Framework to recognize it, we need to write our own convention, this is because Entity Framework only recognizes out of the box a number of SQL Server built-in functions. We can write one as this:

public class FreetextConvention : IStoreModelConvention<EdmModel>

{

    public static readonly FreetextConvention Instance = new FreetextConvention();


    public void Apply(EdmModel item, DbModel model)

    {

        var valueParameter = FunctionParameter.Create("column", this.GetStorePrimitiveType(model, PrimitiveTypeKind.String), ParameterMode.In);

        var formatParameter = FunctionParameter.Create("value", this.GetStorePrimitiveType(model, PrimitiveTypeKind.String), ParameterMode.In);

        var returnValue = FunctionParameter.Create("result", this.GetStorePrimitiveType(model, PrimitiveTypeKind.Boolean), ParameterMode.ReturnValue);


        var function = this.CreateAndAddFunction(item, "FREETEXT", new[] { valueParameter, formatParameter }, new[] { returnValue });

    }


    protected EdmFunction CreateAndAddFunction(EdmModel item, String name, IList<FunctionParameter> parameters, IList<FunctionParameter> returnValues)

    {

        var payload = new EdmFunctionPayload { StoreFunctionName = name, Parameters = parameters, ReturnParameters = returnValues, Schema = this.GetDefaultSchema(item), IsBuiltIn = true };

        var function = EdmFunction.Create(name, this.GetDefaultNamespace(item), item.DataSpace, payload, null);


        item.AddItem(function);


        return (function);

    }


    protected EdmType GetStorePrimitiveType(DbModel model, PrimitiveTypeKind typeKind)

    {

        return (model.ProviderManifest.GetStoreType(TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(typeKind))).EdmType);

    }


    protected String GetDefaultNamespace(EdmModel layerModel)

    {

        return (layerModel.GlobalItems.OfType<EdmType>().Select(t => t.NamespaceName).Distinct().Single());

    }


    protected String GetDefaultSchema(EdmModel layerModel)

    {

        return (layerModel.Container.EntitySets.Select(s => s.Schema).Distinct().SingleOrDefault());

    }

}

This registers a FREETEXT function with two string parameters and returning a boolean. All is fine, we add it to the DbContext in OnModelCreating:

modelBuilder.Conventions.Add(FreetextConvention.Instance);

You might have noticed the usage of a Instance static field, this is because, since the FreetextConvention class is stateless, there’s no point in creating many of them, we can just use the same instance.

Now, if we issue a LINQ query as:

var customers = ctx.Customers.Where(x => x.Name.Freetext("ricardo")).ToList();

It will fail miserably, complaining about this SQL fragment:

WHERE ((FREETEXT(name, N'ricardo') = 1)

The “= 1” part is here because the function is prototyped as boolean, which maps to SQL Server’s BIT data type, and the value for true is 1. Apparently, SQL Server does not support comparisons of some functions with 1; but if we run it as:

WHERE ((FREETEXT(name, N'ricardo'))

without the explicit comparison, it works perfectly. So, all we have to do is get rid of “= 1”. Fortunately, Entity Framework, as of version 6, offers some very nice extensibility points. There are at least two ways by which we can achieve this:

  • By intercepting the command tree;
  • By intercepting the raw SQL.

Here we will use option #2 and leave command trees for another post.

We need to identity something with a format of “FREETEXT(something) = 1”. We can do it using a regular expression, and the interception of the SQL command can be achieved by implementing IDbCommandInterceptor (no reference documentation yet, but I have reported it and it will soon be fixed, hopefully) and registering one such instance in the DbInterception (same) static class. An IDbCommandInterceptor implementation might look like this:

public class FreetextInterceptor : IDbCommandInterceptor

{

    public static readonly FreetextInterceptor Instance = new FreetextInterceptor();


    private static readonly Regex FreetextRegex = new Regex(@"FREETEXT\(([^)]+\))\) = 1");


    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<Int32> interceptionContext)

    {

    }


    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<Int32> interceptionContext)

    {

    }


    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)

    {

    }


    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)

    {

        var matches = FreetextRegex.Matches(command.CommandText);


        if (matches.Count > 0)

        {

            command.CommandText = FreetextRegex.Replace(command.CommandText, "FREETEXT($1)");

        }

    }


    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<Object> interceptionContext)

    {

    }


    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<Object> interceptionContext)

    {

    }

}

You can see that the only method we’re interested in is ReaderExecuting (again, no documentation available), with is the one that will be called just before a SQL SELECT query is sent to the database. In here we analyze the CommandText property of the DbCommand and get rid of the “= 1” clause, using a regular expression. Finally, we need to register the interceptor before we issue the query, maybe in the static constructor of our DbContext:

DbInterception.Add(FreetextInterceptor.Instance);

And now we can finally execute our query:

var customers = ctx.Customers.Where(x => x.Name.Freetext("ricardo")).ToList();

And that’s it. Don’t forget that in order for this to work, you need to enable Full Text Search.

ASP.NET Web Forms Extensibility: Control Builder Interceptors

After my previous post on Control Builders, what could possibly come next? Of course, Control Builder Interceptors! Not much documentation on this one, which is a shame, because it is an even more powerful feature that was recently introduced in ASP.NET 4.5.

A Control Builder Interceptor inherits from, unsurprisingly, ControlBuilderInterceptor. This is configured for the whole application, in the Web.config file, in the compilation section, by a controlBuilderInterceptorType (sorry, no link, since the ASP.NET 4.5 documentation is not online) attribute:

<compilation targetFramework="4.5" controlBuilderInterceptorType="MyNamespace.MyControlBuilderInterceptor, MyAssembly" />

Similarly to Control Builders, a Control Builder Interceptor allows us to:

Granted, less than Control Builders, but the point here is that this is fired for all markup-declared controls, not just those that have a specific Control Builder applied to. With that in mind, we can write code like this:

public class MyControlBuilderInterceptor : ControlBuilderInterceptor

{

    //raised for every control on markup

    public static event Action<ControlInterceptedEventArgs> ControlIntercepted;

 

    public override void OnProcessGeneratedCode(ControlBuilder controlBuilder, CodeCompileUnit codeCompileUnit, CodeTypeDeclaration baseType, CodeTypeDeclaration derivedType, CodeMemberMethod buildMethod, CodeMemberMethod dataBindingMethod, IDictionary additionalState)

    {

        var controlDeclaration = buildMethod.Statements[0] as CodeVariableDeclarationStatement;

 

        if (controlDeclaration != null)

        {

            var controlName = controlDeclaration.Name;

 

            buildMethod.Statements.Insert(buildMethod.Statements.Count - 1, new CodeSnippetStatement(String.Concat(this.GetType().FullName, ".Intercept(@", controlName, ");")));

        }

 

        base.OnProcessGeneratedCode(controlBuilder, codeCompileUnit, baseType, derivedType, buildMethod, dataBindingMethod, additionalState);

    }

 

    public override void PreControlBuilderInit(ControlBuilder controlBuilder, TemplateParser parser, ControlBuilder parentBuilder, Type type, String tagName, String id, IDictionary attributes, IDictionary additionalState)

    {

        if ((attributes != null) && (attributes.Contains("Text") == true))

        {

            //make property value uppercase

            attributes["Text"] = (attributes["Text"] as String).ToUpper();

        }

 

        base.PreControlBuilderInit(controlBuilder, parser, parentBuilder, type, tagName, id, attributes, additionalState);

    }

 

    public static void Intercept(Control instance)

    {

        var handler = ControlIntercepted;

 

        if (handler != null)

        {

            handler(new ControlInterceptedEventArgs(instance));

        }

    }

}

And there you have it. By adding an event handler to MyControlBuilderInterceptor.ControlIntercepted, we can analyze and change the properties of every control:

[Serializable]

public sealed class ControlInterceptedEventArgs : EventArgs

{

    public ControlInterceptedEventArgs(Control control)

    {

        this.Control = control;

    }

 

    public Control Control { get; private set; }

}

 

MyControlBuilderInterceptor.ControlIntercepted += e =>

{

    var myControl = e.Control as MyControl;

    

    if (myControl != null)

    {

        myControl.Text = myControl.Text.ToUpper();

    }

};

Stay tuned for more extensibility points of your favorite framework!

ASP.NET Web Forms Extensibility: Control Builders

One of the most often ignored extensibility point in Web Forms is the Control Builder. Control Builders are subclasses of ControlBuilder (or other more specialized, such as FileLevelPageControlBuilder, for pages, or FileLevelMasterPageControlBuilder, for master pages) that can be specified per class. It controls some aspects of a control instance:

It also allows overriding a couple of things:

  • The parameters specified in the markup (Init);
  • What to do when the control builder is added to a parent control builder (OnAppendToParentBuilder);
  • Modify the code that will be generated in the code-behind class that is produced by ASP.NET or the code that will be used to instantiate the control (ProcessGeneratedCode);
  • Change the tag’s inner textual content (SetTagInnerText);
  • Etc.

This is a powerful mechanism, which has even been used to allow generic control classes. We apply a control builder through a ControlBuilderAttribute (for regular controls) or FileLevelControlBuilderAttribute for pages, master pages or user controls.

I won’t go into many details, but instead I will focus on the Init and ProcessGeneratedCode methods.

Init let’s us do things such as:

public override void Init(TemplateParser parser, ControlBuilder parentBuilder, Type type, String tagName, String id, IDictionary attribs)

{

    if (type == typeof(SomeBaseControl)

    {

        //replace the control's type for another one

        type = typeof(SomeDerivedControl);

 

        //convert an hypothetical Text property value to upper case

        attribs["Text"] = (attribs["Text"] as String).ToUpper();

    }

 

    base.Init(parser, parentBuilder, type, tagName, id, attribs);

}

And ProcessGeneratedCode, messing with the generated page class:

public override void ProcessGeneratedCode(CodeCompileUnit codeCompileUnit, CodeTypeDeclaration baseType, CodeTypeDeclaration derivedType, CodeMemberMethod buildMethod, CodeMemberMethod dataBindingMethod)

{

    //add some interface to the generated page class

    derivedType.BaseTypes.Add(typeof(ISomeInterface));

 

    //add a property implementation to the generated page class

    var prop = new CodeMemberProperty();

    prop.Attributes = MemberAttributes.Public;

    prop.Name = "SomeProperty";

    prop.Type = new CodeTypeReference(typeof(String));    

    prop.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Hello, World, from a generated property!")));

    

    derivedType.Members.Add(prop);

 

    base.ProcessGeneratedCode(codeCompileUnit, baseType, derivedType, buildMethod, dataBindingMethod);

}

But also something MUCH more fun! Imagine you are using an IoC container – I will use Unity, but you can use whatever you want. We might have something like this in Application_Start (or whatever method spawned from it);

var unity = new UnityContainer();

unity.RegisterInstance<MyControl>(new MyControl { Text = "Bla bla" });

ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(unity));

Notice I am using the Common Service Locator to abstract the IoC container and to make the code independent of it. Here, I am assigning a static instance to the MyControl type, in essence, a singleton.

Now, we can change our control builder so as to have the control build method return this instance:

public override void ProcessGeneratedCode(CodeCompileUnit codeCompileUnit, CodeTypeDeclaration baseType, CodeTypeDeclaration derivedType, CodeMemberMethod buildMethod, CodeMemberMethod dataBindingMethod)

{

    //return ServiceLocator.Current.GetInstance(typeof(MyControl));

    var type = Type.GetType((buildMethod.Statements[0] as CodeVariableDeclarationStatement).Type.BaseType);

    var currentProperty = new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof (ServiceLocator)), "Current");

    var getInstance = new CodeMethodInvokeExpression(currentProperty, "GetInstance", new CodeTypeOfExpression(type));

    var @cast = new CodeCastExpression(type, getInstance);

    var @return = new CodeMethodReturnStatement(@cast);

 

    buildMethod.Statements.Clear();

    buildMethod.Statements.Add(@return);

 

    base.ProcessGeneratedCode(codeCompileUnit, baseType, derivedType, buildMethod, dataBindingMethod);

}

In case you didn’t notice, what this does is, every time the MyControl control is instantiated in a page, for every request, ASP.NET will always return the same instance!

Now, I am not saying that you SHOULD do this, but only that you CAN do this! Winking smile

Take care out there…

Lesser-Known NHibernate Features: Filtering an Unloaded Collection

Suppose you have an entity with a collection of other entities (one to many, many to many); this collection is normally represented by some property implementing IEnumerable<T>, or one some more specific interface.

If we want to query this collection, we normally have to load all of its items. For indexed collections, it is possible to use extra-lazy laziness, which means NHibernate will only load one item at a time, instead of all at once, but this might even be worse, because it would result in multiple SELECT statements.

NHibernate offers a nice mechanism to filter and order a collection without actually loading all of its items; it’s the CreateFilter method of the ISession, and we use it like this:

   1: //get an order

   2: var order = session.Query<Order>().First();

   3:  

   4: //all order details of this order where quantity is greater than one

   5: var detailsWithMoreThanOneItem = session.CreateFilter(order.Details, "WHERE Quantity > 1").List<OrderDetail>();

   6:  

   7: //all order details of this order sorted by their quantity in descending order

   8: var detailsSortedByQuantityInDescendingOrder = session.CreateFilter(o.Details, "ORDER BY Quantity DESC").List<OrderDetail>();

I even once wrote a helper method for querying collections with LINQ without actually loading them; its usage is:

   1: //all order details of this order where quantity is greater than one

   2: var detailsWithMoreThanOneItem = order.Details.Query().Where(d => d.Quantity > 1).ToList();

The Query extension method will check to see if the collection has already been loaded, in which case, it resorts to LINQ to Objects, otherwise, it generates a proper LINQ query. You can find the source code here.

Custom Entity Framework Code First Convention for Discriminator Values

Since version 6, Entity Framework Code First allows the injection of custom conventions. These conventions define rules that will be applied by default to all mapped entities and properties, unless explicitly changed.

The conventions API includes a couple of interfaces: IConvention (marker only, should always be included), IConceptualModelConvention<T> (for the conceptual space of the model) and IStoreModelConvention<T> (for the store, or physical, side of the model). Worthy of mention, there is also a convenience class, Convention, that allows access to all mapped types and properties and doesn’t override any of the other conventions, and also TypeAttributeConfigurationConvention<T>, for tying a convention to a custom attribute. Some of the included attributes leverage these interfaces to configure some aspects of the mappings at design time, other configuration needs to be done explicitly in an override of OnModelCreating.

Entity Framework permits using a column for distinguishing between different types, when the Table Per Class Hierarchy / Single Table Inheritance pattern (please see Entity Framework Code First Inheritance for more information) is used for mapping a hierarchy of classes to a single table, as part of “soft delete” solutions, or, less known, for differentiating between multiple tenants. This column is called a discriminator.

In order to configure an entity to use a discriminator column, there is no out of the box attribute, so we must resort to code configuration:

   1: protected override void OnModelCreating(DbModelBuilder modelBuilder)

   2: {

   3:     modelBuilder.Entity<MyMultiTenantEntity>().Map(m => m.Requires("tenant_id").HasValue("first_tenant"));

   4:  

   5:     base.OnModelCreating(modelBuilder);

   6: }

Because there’s really no need to keep repeating this code, let’s implement an attribute for indicating a discriminator column in an entity:

   1: [Serializable]

   2: [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]

   3: public sealed class DiscriminatorAttribute : Attribute

   4: {

   5:     public DiscriminatorAttribute(String columnName, Object discriminatorValue)

   6:     {

   7:         this.ColumnName = columnName;

   8:         this.DiscriminatorValue = discriminatorValue;

   9:     }

  10:  

  11:     public String ColumnName { get; private set; }

  12:  

  13:     public Object DiscriminatorValue { get; private set; }

  14:  

  15:     public override Boolean Equals(Object obj)

  16:     {

  17:         var other = obj as DiscriminatorAttribute;

  18:  

  19:         if (other == null)

  20:         {

  21:             return (false);

  22:         }

  23:  

  24:         return ((this.ColumnName == other.ColumnName) && (Object.Equals(this.DiscriminatorValue, other.DiscriminatorValue) == true));

  25:     }

  26:  

  27:     public override Int32 GetHashCode()

  28:     {

  29:         return (String.Concat(this.ColumnName, ":", this.DiscriminatorValue).GetHashCode());

  30:     }

  31: }

As you can see, the DiscriminatorAttribute attribute can only be applied to a class, at most once. This makes sense, because most likely you will only have a single discriminator column per entity:

   1: [Discriminator("tenant_id", "first_tenant")]

   2: public class MyMultiTenantEntity

   3: {

   4:     //...

   5: }

You need to specify both a column name and a discriminator value, which can be of any type, usually, a string or an integer.

Now, let’s write a custom convention that knows how to handle our custom attribute and perform the mapping:

WARNING! DYNAMICS AND REFLECTION AHEAD!

PROCEED WITH CAUTION!

   1: public sealed class DiscriminatorConvention : TypeAttributeConfigurationConvention<DiscriminatorAttribute>

   2: {

   3:     private static readonly MethodInfo entityMethod = typeof(DbModelBuilder).GetMethod("Entity");

   4:     private static readonly MethodInfo hasValueMethod = typeof(ValueConditionConfiguration).GetMethods().Single(m => (m.Name == "HasValue") && (m.IsGenericMethod == false));

   5:  

   6:     private readonly DbModelBuilder modelBuilder;

   7:     private readonly ISet<Type> types = new HashSet<Type>();

   8:  

   9:     public DiscriminatorConvention(DbModelBuilder modelBuilder)

  10:     {

  11:         this.modelBuilder = modelBuilder;

  12:     }

  13:  

  14:     public override void Apply(ConventionTypeConfiguration configuration, DiscriminatorAttribute attribute)

  15:     {

  16:         if (this.types.Contains(configuration.ClrType) == true)

  17:         {

  18:             //if the type has already been processed, bail out

  19:             return;

  20:         }

  21:  

  22:         //add the type to the list of processed types

  23:         this.types.Add(configuration.ClrType);

  24:  

  25:         dynamic entity = entityMethod.MakeGenericMethod(configuration.ClrType).Invoke(modelBuilder, null);

  26:  

  27:         Action<dynamic> action = arg =>

  28:         {

  29:             var valueConditionConfiguration = arg.Requires(attribute.ColumnName);

  30:             hasValueMethod.Invoke(valueConditionConfiguration, new Object[] { attribute.DiscriminatorValue });

  31:         };

  32:  

  33:         entity.Map(action);

  34:     }

  35: }

This class uses a bit of dynamics and reflection because types are not known at compile time, and hence we cannot use generics directly. Because the Apply method will be called multiple times, we need to keep track of which entities have already been processed by this convention, so as to avoid reprocessing them. We need to pass it the instance of DbModelBuilder, because otherwise our custom convention would have no way to apply the mapping, but I think it is a reasonable trade off.

Et voilà! In order to make use of it, we need to register the convention in OnModelCreating:

   1: protected override void OnModelCreating(DbModelBuilder modelBuilder)

   2: {

   3:     modelBuilder.Conventions.Add(new DiscriminatorConvention(modelBuilder));

   4:  

   5:     base.OnModelCreating(modelBuilder);

   6: }

And that’s it! Happy conventions! Winking smile

Lesser-Known NHibernate Features: Result Transformers

A result transformer, in NHibernate, is some class that implements the IResultTransformer interface:

   1: public interface IResultTransformer

   2: {

   3:     IList TransformList(IList collection);

   4:     Object TransformTuple(Object[] tuple, String[] aliases);

   5: }

Most query APIs, except LINQ, support specifying a result transformer. So, what is a result transformer used for? Just what the name says: it turns the values obtained from a query into some object. Normally, we just let NHibernate transform these values into instances of our entities, but we may want to do something different, either because we haven’t mapped some class that we want to use, or because we are not returning all of the entity’s properties, etc.

NHibernate includes some result transformers:

  • AliasToBeanResultTransformer: allows to transform a result to a user specified class which will be populated via setter methods or fields matching the alias names;
  • AliasToBeanConstructorResultTransformer: identical to AliasToBeanResultTransformer, but we specify a constructor for creating new instances of the target class;
  • AliasToEntityMapResultTransformer: returns a dictionary where the keys are the aliases and the values the corresponding columns;
  • AliasedTupleSubsetResultTransformer: ignores a tuple element if its corresponding alias is null;
  • CacheableResultTransformer: used to transform tuples to a value(s) that can be cached;
  • DistinctRootEntityResultTransformer: for joined queries, returns distinct root entities only;
  • PassThroughResultTransformer: just returns the row as it was obtained from the database;
  • RootEntityResultTransformer; returns the root entity of a joined query;
  • ToListResultTransformer: transforms each result row from a tuple into a IList, such that what you end up with is a IList of ILists.

All of these can be obtained from static properties in class NHibernate.Transform.Transformers. NHibernate implicitly uses some of these, for example, LINQ queries always use DistinctRootEntityResultTransformer.

It is easy to build our own transformer. Have a look at the following example:

   1: public class ExpressionsResultTransformer : IResultTransformer

   2: {

   3:     private readonly Type type;

   4:     private readonly Func<Object> constructorFunc;

   5:     private readonly ConstructorInfo constructor;

   6:     private readonly Object[] parameters;

   7:     private readonly Dictionary<Int32, String> expressions = new Dictionary<Int32, String>();

   8:     private PropertyDescriptorCollection props;

   9:  

  10:     public ExpressionsResultTransformer(ConstructorInfo constructor, params Object[] parameters)

  11:     {

  12:         this.constructor = constructor;

  13:         this.parameters = parameters;

  14:     }

  15:  

  16:     public ExpressionsResultTransformer(Func<Object> constructorFunc)

  17:     {

  18:         this.constructorFunc = constructorFunc;

  19:     }

  20:  

  21:     public ExpressionsResultTransformer(Type type)

  22:     {

  23:         this.type = type;

  24:     }

  25:  

  26:     private Object CreateInstance()

  27:     {

  28:         if (this.type != null)

  29:         {

  30:             return (Activator.CreateInstance(this.type));

  31:         }

  32:         else if (this.constructorFunc != null)

  33:         {

  34:             return (this.constructorFunc());

  35:         }

  36:         else

  37:         {

  38:             return (this.constructor.Invoke(this.parameters));

  39:         }

  40:     }

  41:  

  42:     public ExpressionsResultTransformer Add(Int32 index, String property)

  43:     {

  44:         this.expressions[index] = property;

  45:         return (this);

  46:     }

  47:  

  48:     public ExpressionsResultTransformer Add(params String[] properties)

  49:     {

  50:         foreach (var property in properties)

  51:         {

  52:             this.Add(property);

  53:         }

  54:  

  55:         return (this);

  56:     }

  57:  

  58:     public ExpressionsResultTransformer Add(String property)

  59:     {

  60:         var max = this.expressions.Keys.DefaultIfEmpty(-1).Max();

  61:         return (this.Add(max + 1, property));

  62:     }

  63:  

  64:     public static ExpressionsResultTransformer Add<T>(params String[] properties) where T : new()

  65:     {

  66:         return (new ExpressionsResultTransformer<T>().Add(properties));

  67:     }

  68:  

  69:     #region IResultTransformer Members

  70:  

  71:     IList IResultTransformer.TransformList(IList collection)

  72:     {

  73:         return (collection);

  74:     }

  75:  

  76:     Object IResultTransformer.TransformTuple(Object[] tuple, String[] aliases)

  77:     {

  78:         var entity = this.CreateInstance();

  79:  

  80:         if (this.props == null)

  81:         {

  82:             this.props = TypeDescriptor.GetProperties(entity);

  83:         }

  84:  

  85:         foreach (var expression in this.expressions)

  86:         {

  87:             this.props[expression.Value].SetValue(entity, tuple[expression.Key]);

  88:         }

  89:  

  90:         return (entity);

  91:     }

  92:  

  93:     #endregion

  94: }

  95:  

  96: public sealed class ExpressionsResultTransformer<T> : ExpressionsResultTransformer where T : new()

  97: {

  98:     public ExpressionsResultTransformer() : base(typeof(T))

  99:     {

 100:     }

 101:  

 102:     public ExpressionsResultTransformer(Func<T> constructor) : base(new Func<Object>(() => (Object) constructor()))

 103:     {

 104:     }

 105:  

 106:     public ExpressionsResultTransformer(ConstructorInfo constructor, params Object[] parameters) : base(constructor, parameters)

 107:     {

 108:     }

 109: }

The TransformTuple method is the one used to turn each returned record into an instance of something. TransformList is called at the end, when all the records have been processed.

The ExpressionResultTransformer class allows us to select which indexes, in the database record, map to which properties in some entity. For our convenience, it offers a number of options to construct an instance (type, constructor + parameters and delegate). We would use it like this:

   1: var products = session.CreateSQLQuery("select p.Name, p.Price, p.ProductId from Product p").SetResultTransformer(ExpressionsResultTransformer.Add<Product>("Name", "Price", "ProductId")).List<Product>();

Getting the SQL for HQL and Criteria Queries

OK, so, I already showed how we can get the SQL that was generated from a LINQ query. Of course, we can do the same for both HQL and Criteria APIs as well (QueryOver is just a wrapper around Criteria, mind you).

So, for HQL (and SQL), it goes like this:

   1: public static class QueryExtensions

   2: {

   3:     private static readonly PropertyInfo sessionProperty = typeof (QueryImpl).GetProperty("Session", BindingFlags.NonPublic | BindingFlags.Instance);

   4:  

   5:     public static String ToSql(this IQuery query)

   6:     {

   7:         if (query is QueryImpl)

   8:         {

   9:             var session = sessionProperty.GetValue(query, null) as ISession;

  10:             var sessionImpl = session.GetSessionImplementation();

  11:             var translatorFactory = new ASTQueryTranslatorFactory();

  12:             var translators = translatorFactory.CreateQueryTranslators(query.QueryString, null, false, sessionImpl.EnabledFilters, sessionImpl.Factory);

  13:  

  14:             return translators[0].SQLString;

  15:         }

  16:         else if (query is SqlQueryImpl)

  17:         {

  18:             return (query.QueryString);

  19:         }

  20:  

  21:         throw (new NotSupportedException("Query type is not supported."));

  22:     }

  23: }

You can pass any implementation if IQuery, such as one produced from ISession.CreateQuery() or ISession.CreateSQLQuery(). The static field is merely for performance reasons.

As for Criteria:

   1: public static class CriteriaExtensions

   2: {

   3:     public static String ToSql(this ICriteria criteria)

   4:     {

   5:         var criteriaImpl = criteria as CriteriaImpl;

   6:         var sessionImpl = criteriaImpl.Session;

   7:         var factory = sessionImpl.Factory;

   8:         var implementors = factory.GetImplementors(criteriaImpl.EntityOrClassName);

   9:         var loader = new CriteriaLoader(factory.GetEntityPersister(implementors[0]) as IOuterJoinLoadable, factory, criteriaImpl, implementors[0], sessionImpl.EnabledFilters);

  10:  

  11:         return loader.SqlString.ToString();

  12:     }

  13: }

And finally, QueryOver, just a small wrapper around the Criteria version:

   1: public static class QueryOverExtensions

   2: {

   3:     public static String ToSql(this IQueryOver queryOver)

   4:     {

   5:         var criteria = queryOver.UnderlyingCriteria;

   6:         return (criteria.ToSql());

   7:     }

   8: }

Hope you find this useful! Winking smile

Adding Support for ISupportInitialize in NHibernate

The .NET ISupportInitialize interface is used when we want to support staged initialization for objects. Its BeginInit method is called when initialization is about to start and EndInit when it is finished.

If we want, it is easy to add support for it in NHibernate. An option would be:

  • BeginInit is called when the object is instantiated, like when NHibernate has loaded a record from the database and is about to hydrate the entity, and immediately after the Id property is set;
  • EndInit is called after all properties are set.

We do this by using a custom interceptor, like we have in the past. We start by writing a class that inherits from EmptyInterceptor, and implements the listener interface for the PostLoad event, IPostLoadEventListener:

   1: public sealed class SupportInitializeInterceptor : EmptyInterceptor, IPostLoadEventListener

   2: {

   3:     private ISession session = null;

   4:  

   5:     public override void SetSession(ISession session)

   6:     {

   7:         this.session = session;

   8:         base.SetSession(session);

   9:     }

  10:  

  11:     public override Object Instantiate(String clazz, EntityMode entityMode, Object id)

  12:     {

  13:         var listeners = (this.session.SessionFactory as SessionFactoryImpl).EventListeners;

  14:         var metadata = this.session.SessionFactory.GetClassMetadata(clazz);

  15:         var proxy = metadata.Instantiate(id, entityMode);

  16:         var initializable = proxy as ISupportInitialize;

  17:  

  18:         if (initializable != null)

  19:         {

  20:             initializable.BeginInit();

  21:         }

  22:  

  23:         if (listeners.PostLoadEventListeners.OfType<SupportInitializeInterceptor>().Any() == false)

  24:         {

  25:             listeners.PostLoadEventListeners = listeners.PostLoadEventListeners.Concat(new IPostLoadEventListener[] { this }).ToArray();

  26:         }

  27:  

  28:         return (proxy);

  29:     }

  30:  

  31:     #region IPostLoadEventListener Members

  32:  

  33:     void IPostLoadEventListener.OnPostLoad(PostLoadEvent @event)

  34:     {

  35:         var initializable = @event.Entity as ISupportInitialize;

  36:  

  37:         if (initializable != null)

  38:         {

  39:             initializable.EndInit();

  40:         }

  41:     }

  42:  

  43:     #endregion

  44: }

Then, before creating a session factory, we need to register it in the Configuration instance:

   1: var sessionFactory = cfg.SetInterceptor(new SupportInitializeInterceptor()).BuildSessionFactory();

Now, if your entity implements ISupportInitialize, NHibernate will automagically call its methods at the proper time. As simple as this! Winking smile