5 votes

Est-ce que la bibliothèque d'entreprise 5.0 met en cache les mappings entre le datareader et les classes personnalisées pour les méthodes d'accès ?

Je voulais savoir si les méthodes Accessor de Enterprise Library 5.0 mettaient en cache les champs du datareader ainsi que des classes personnalisées pour des raisons de performances, de sorte qu'elles ne recherchent pas les noms des champs des classes personnalisées en utilisant les réflexions et ne recherchent pas les noms des champs du datareader lors du mappage du datareader aux objets ? Parce que c'est une opération assez coûteuse de faire correspondre les champs des classes personnalisées aux champs du datareader pour chaque accès / bloc de 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; }
}

6voto

Marc Gravell Points 482669

De le code cette méthode passe par :

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

puis à

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

qui passe par

return MapAllProperties().Build();

qui est :

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

donc non, je ne vois aucune preuve de mise en cache à cet endroit. Vous pourriez en ajouter, ou vous pourriez utiliser un domaine qui fait déjà de la mise en cache pour les matérialisateurs et les paramétrages (*cough*). dapper-dot-net *cough*)

2voto

Raj Points 4661

Voici un hack facile et agréable suggéré par l'équipe d'assistance d'entlib (vous pouvez consulter le fil de discussion complet à l'adresse suivante http://entlib.codeplex.com/discussions/281833 ) :

randylevy Lun à 11:39 PM Non, il n'y a pas de mise en cache du RowMapper. La seule mise en cache que je connaisse pour l'accès aux données est la suivante Application Block est la mise en cache des paramètres de la procédure stockée.

Si vous utilisez le mappeur par défaut, vous pouvez mettre les résultats en cache. et les passer dans la méthode ExecuteSqlStringAccessor puisqu'elle supporte supporte les surcharges IRowMapper et IResultSetMapper.

Par exemple :

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 De nouveau à partir d'EntLib (une solution encore meilleure) :

Merci. Peut-être que cela peut être mis sur la table pour Enterprise Library 6 puisque cela semble être une bonne idée ?

Juste pour le fun, j'ai un peu affiné l'exemple pour stocker le RowMapperCache en tant que singleton à l'intérieur de l'EnterpriseLibraryContainer de façon à ce qu'il puisse être récupéré comme les autres objets de l'Enterprise Library. Bien que bien qu'il ne s'agisse pas d'une classe "native" de l'Enterprise Library, le RowMapperCache est utilisé uniquement avec Enterprise Library. Il n'est donc pas nécessaire de la stocker dans le conteneur le conteneur (surtout si vous n'utilisez pas l'IoC complet de Unity).

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X