5

想知道 Enterprise Library 5.0 的 Accessor 方法是否缓存 datareader 的字段以及自定义类以提高性能,这样它就不会使用反射在自定义类上查找字段名称,并且在将 datareader 映射到时不会在 datareader 上查找字段名称对象?因为将自定义类字段映射到每个访问/代码块的数据读取器字段是一项非常昂贵的操作

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

2 回答 2

6

代码中,该方法通过:

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

然后到

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

通过

return MapAllProperties().Build();

这是:

    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;
    }

所以不行; 我没有看到那里有任何缓存的证据。您可以添加一些,或者您可以使用已经完成物化器和参数化缓存的 dometh (*cough* dapper-dot-net *cough*)

于 2011-12-05T13:12:57.427 回答
2

这是 entlib 支持团队建议的一个简单而漂亮的 hack(您可以在http://entlib.codeplex.com/discussions/281833查看完整线程):

randylevy 星期一晚上 11:39 不,RowMapper 没有任何缓存。我所知道的数据访问应用程序块的唯一缓存是存储过程参数缓存。

如果您使用的是默认映射器,那么您可以自己缓存结果并传递给 ExecuteSqlStringAccessor 方法,因为它支持 IRowMapper 和 IResultSetMapper 重载。

例如:

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);

再次从 EntLib更新(更好的解决方案):

谢谢。也许,它可以放在 Enterprise Library 6 的桌面上,因为它看起来是个好主意?

只是为了好玩,我对示例进行了一些改进,将 RowMapperCache 作为单例存储在 EnterpriseLibraryContainer 中,以便可以像其他 Enterprise Library 对象一样检索它。尽管不是企业库“本机”类,但 RowMapperCache 仅与企业库一起使用,因此将其存储在容器中并不是一个巨大的飞跃(尤其是如果您没有使用完整的 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();
        }
    }
}
于 2011-12-06T08:31:41.060 回答