Maps enterprise library 5.0 caching between datareader and user classes for accessor methods

I wanted to know if the Accessor Enterprise Library 5.0 methods cache datareader fields as well as user classes for performance so that they do not look for field names on user classes using reflections and do not look for field names in datareader when matching datareader with objects? Since its quite an expensive operation to map custom class fields to datareader fields for each access block / code

public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Database db = EnterpriseLibraryContainer.Current.GetInstance<Database>(); var r = db.ExecuteSqlStringAccessor<Region>("SELECT * FROM Region"); } } public class Region { public string RegionnId { get; set; } public string Name { get; set; } } 
+4
source share
2 answers

From the code, this method goes through:

 public static IEnumerable<TResult> ExecuteSqlStringAccessor<TResult>(this Database database, string sqlString) where TResult : new() { return CreateSqlStringAccessor<TResult>(database, sqlString).Execute(); } 

then to

 IRowMapper<TResult> defaultRowMapper = MapBuilder<TResult>.BuildAllProperties(); 

which goes through

 return MapAllProperties().Build(); 

which the:

  public static IMapBuilderContext<TResult> MapAllProperties() { IMapBuilderContext<TResult> context = new MapBuilderContext(); var properties = from property in typeof(TResult).GetProperties(BindingFlags.Instance | BindingFlags.Public) where IsAutoMappableProperty(property) select property; foreach (var property in properties) { context = context.MapByName(property); } return context; } 

so no; I do not see any evidence of any caching. You could add some of them, or you could use something that already caches materializer and parameterization (* cough * dapper-dot-net * cough *)

+5
source

Here is a simple and nice hack suggested by the entlib support team (you can check the whole topic at http://entlib.codeplex.com/discussions/281833 ):

randylevy Mon at 23:39 No, no RowMapper caching. The only caching that I know for accessing data from the Application Block is the caching of stored procedure parameters.

If you use the default mapping, you can cache the results and go to the ExecuteSqlStringAccessor method as it supports IRowMapper and IResultSetMapper overloads.

eg:.

 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 (even better solution):

Thanks. Perhaps it can be put on the table for Enterprise Library 6 as it seems like a good idea?

Just for fun, I refined the example a bit to store RowMapperCache as a singleton inside an EnterpriseLibraryContainer so that it can be retrieved similarly to other Enterprise Library objects. Despite the fact that it is not a β€œprivate” class of the corporate library, RowMapperCache is used only with the corporate library, so this is not a huge leap for storage in the container (especially if you are not 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(); } } } 
+2
source

Source: https://habr.com/ru/post/1384695/


All Articles