Here is an easy and nice hack suggested by entlib support team (you can check the full thread at http://entlib.codeplex.com/discussions/281833):
randylevy Mon at 11:39 PM No, there isn't any caching of the
RowMapper. The only caching I'm aware of for the Data Access
Application Block is stored procedure parameter caching.
If you are using the default mapper then you could cache the results
yourself and pass into the ExecuteSqlStringAccessor method since it
supports IRowMapper and IResultSetMapper overloads.
E.g.:
public class RowMapperCache
{
private Dictionary<Type, object> cache = new Dictionary<Type, object>();
private object locker = new object();
public IRowMapper<T> GetCachedMapper<T>() where T : new()
{
Type type = typeof(T);
lock (locker)
{
if (!Contains(type))
{
cache[type] = MapBuilder<T>.BuildAllProperties();
}
}
return cache[type] as IRowMapper<T>;
}
private bool Contains(T type)
{
return cache.ContainsKey(type);
}
}
// retrieve default mapper and cache it
IRowMapper<Region> regionMapper = rowMapperCache.GetCachedMapper<Region>();
var db = EnterpriseLibraryContainer.Current.GetInstance<Database>();
var r = db.ExecuteSqlStringAccessor<Region>("SELECT * FROM Region", regionMapper);
UPDATE From EntLib again (an even better solution):
Thanks. Maybe, it can be put on the table for Enterprise Library 6
since it seems like a good idea?
Just for fun, I refined the example a bit to store the RowMapperCache
as a singleton inside of the EnterpriseLibraryContainer so that it can
be retrieved similar to other Enterprise Library objects. Although
not an Enterprise Library "native" class, the RowMapperCache is used
only with Enterprise Library so it's not a huge leap to store it in
the container (especially if you aren't using full Unity IoC).
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel.Unity;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.Unity;
namespace RowMapperConsole
{
public class Region {}
public class RowMapperCache
{
private Dictionary<Type, object> cache = new Dictionary<Type, object>();
private object locker = new object();
public IRowMapper<T> GetCachedMapper<T>() where T : new()
{
Type type = typeof(T);
lock (locker)
{
if (!Contains(type))
{
cache[type] = MapBuilder<T>.BuildAllProperties();
}
}
return cache[type] as IRowMapper<T>;
}
private bool Contains(T type)
{
return cache.ContainsKey(type);
}
}
class Program
{
static void Main(string[] args)
{
ApplicationInitialize();
// ...
IEnumerable<Region> regions = GetRegions();
}
public static void ApplicationInitialize()
{
ConfigureContainer(container =>
{
// Register as Singleton
container.RegisterType<RowMapperCache>(new ContainerControlledLifetimeManager());
});
}
public static void ConfigureContainer(Action<IUnityContainer> action)
{
IUnityContainer container = new UnityContainer();
if (action != null)
action(container);
IContainerConfigurator configurator = new UnityContainerConfigurator(container);
EnterpriseLibraryContainer.ConfigureContainer(configurator, ConfigurationSourceFactory.Create());
IServiceLocator locator = new UnityServiceLocator(container);
EnterpriseLibraryContainer.Current = locator;
}
public static IEnumerable<Region> GetRegions()
{
IRowMapper<Region> regionMapper = EnterpriseLibraryContainer.Current.GetInstance<RowMapperCache>()
.GetCachedMapper<Region>();
var db = EnterpriseLibraryContainer.Current.GetInstance<Database>();
return db.ExecuteSqlStringAccessor<Region>("SELECT * FROM Region", regionMapper).ToList();
}
}
}