企业库 5.0 是否缓存数据读取器和访问器方法的自定义类之间的映射

发布于 2024-12-19 14:20:39 字数 609 浏览 5 评论 0原文

想知道 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; }
}

Wanted to know if the Accessor methods of Enterprise Library 5.0 cache the fields of datareader as well as custom classes for performance such that it does not look up field names on custom classes using reflections and does not look up field names on datareader when mapping datareader to objects? Because its a pretty expensive operation to map custom class fields to datareader fields for every access / code block

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千纸鹤 2024-12-26 14:20:39

代码来看,该方法经过:

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

then 到

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

which经过

return MapAllProperties().Build();

which是:

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

所以不;我没有看到任何缓存的证据。您可以添加一些,或者您可以使用已经实现物化器和参数化缓存的 domething (*咳嗽* dapper-dot-net *咳嗽*)

From the code, that method goes via:

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 via

return MapAllProperties().Build();

which is:

    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 see no evidence of any caching there. You could add some, or you could use domething that already does materializer and parameterization caching (*cough* dapper-dot-net *cough*)

只怪假的太真实 2024-12-26 14:20:39

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

randylevy 周一晚上 11:39 不,没有任何缓存
行映射器。我所知道的唯一用于数据访问的缓存
Application Block是存储过程参数缓存。

如果您使用默认映射器,那么您可以缓存结果
自己并传递到 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 内部的单例,以便它可以
与其他企业库对象类似地检索。虽然
不是企业库“本机”类,而是使用 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();
        }
    }
}

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();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文