65.9K
CodeProject 正在变化。 阅读更多。
Home

如何提高类型化DataSet的创建性能

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.22/5 (13投票s)

2005年5月13日

CDDL

2分钟阅读

viewsIcon

123797

downloadIcon

693

如何提高类型化 DataSet 创建的性能。

引言

在 .NET 环境中用于传递给 N 层应用程序的常见对象是 DataSet 对象。 此外,为了简化 DataSet 对象的使用,我们通常将其定义为强类型 DataSet (使用 XML 架构)。

一个常见的场景是在一层中创建(实例化)类型化的 DataSet,然后将其传递给其他层以进行进一步的逻辑实现。 创建类型化的 DataSet 实际上非常昂贵。 我惊讶地意识到(使用各种分析工具),大约 15%-20% 的应用程序时间浪费在类型化的 DataSet 的构造函数上。

一个建议的解决方案

大多数应用程序使用以下流程:一个新创建的 DataSet 被填充数据(由用户或来自数据库),用一些逻辑更新,保存到数据库,然后最终被丢弃。 然后循环重复。

(有关在需要多个此类 DataSet 实例的情况下可以执行的操作的更多信息,请参阅 备注 部分。)

如果 DataSet 仅创建一次,则会显着提高性能。 因此,建议的解决方案如下:创建一次所需的类型化 DataSet,将其保存到缓存中,并在需要时,在使用 DataSet.Clear() 方法清除其数据后立即返回它。 这样本质上更快吗? 是的,我使用各种分析器进行了测试,DataSet.Clear() 方法比类型化的 DataSet 的构造函数快 2-10 倍 (!!!)。

下面是用于类型化 DataSet 代理的源代码,该代理控制所需类型化 DataSet 的创建。

namespace TypedDSProxy
{
    ///<summary>
    /// Controls creation of typed DataSet.
    /// Singleton.
    ///</summary>
    public class DSProxy
    {
        ///<summary>
        /// Initial size of typed DS cache.
        ///</summary>
        private const int InitialCacheSize = 2;
        ///<summary>
        /// Typed DS cache. 
        ///</summary>
        private Hashtable cache;

        ///<summary>
        /// Instance variable for Singleton pattern.
        ///</summary>
        private static DSProxy DSProxyInstance;

        ///<summary>
        /// Default Constructor.
        ///</summary>
        private DSProxy()
        {
            cache = new Hashtable(InitialCacheSize);
        }
        ///<summary>
        /// Instance method for Singleton pattern.
        ///</summary>
        ///<returns>DSProxy</returns>
        public static DSProxy Instance()
        {
            if(DSProxyInstance == null)
                DSProxyInstance = new DSProxy();
            return DSProxyInstance;
        }

        ///<summary>
        ///    Gets the namespace from the given type.
        ///(The namespace derived from the beginning
        ///      of the type till the first "." char.)
        ///</summary>
        ///<param name="dsType">The string representation
        ///                  of typed DS's type.</param>
        ///<returns>Typed DS's namespace.</returns>
        private string GetNamespace(string dsType)
        {
            try
            {
                return dsType.Substring(0, dsType.IndexOf("."));
            }
            catch(Exception e)
            {
                // write e.Message to log.
                ...
            }
        }

        ///<summary>
        /// Returns an empty typed DataSet according to a given type.
        ///</summary>
        ///<param name="dsType">The string representation
        ///       of typed DS's type.</param>
        ///<returns>Empty typed DS.</returns>
        public DataSet GetDS(string dsType)
        {
            try
            {
                DataSet ds;
                // if the DataSet wasn't created.
                if(cache[dsType] == null)
                {
                    // create it using its assembly.
                    Assembly asm = Assembly.Load(GetNamespace(dsType));
                    ds = (DataSet)asm.CreateInstance(dsType, true);
                    cache.Add(dsType, ds);
                }
                else
                {
                    // else clear it.
                    ds = (DataSet)cache[dsType];
                    ds.Clear();
                }
                return ds;

            }
            catch(Exception e)
            {
                // write e.Message to log.
                ...
            }
        }
    }
}

客户端使用类型化 DataSet 代理,如下所示

class clsClient
{
    ...
    
    public void SomeOperationWithTypedDS()
    {
        OrdersDS ds = 
          (OrdersDS)DSProxy.Instance().GetDS(typeof(OrdersDS).ToString());
        ds.Orders.AddOrdersRow("a", 1, System.DateTime.Now, 
           System.DateTime.Now, System.DateTime.Now, 1, 
           decimal.MinValue, "a", "a", "a", "a", "a", "a");
    }

    ...
}

备注

  • 建议的解决方案不是线程安全的。 如果线程安全是一个问题,可以使用类型化 DataSet 的池。(对象池也解决了需要多个类型化 DataSet 对象的情况。)关于托管对象池的一篇好文章可以在这里找到:使用托管代码进行对象池 - 作者:Scott Sherer。(当线程安全不是问题并且仍然需要多个类型化 DataSet 对象时,可以使用一个更简单的池 - 无对象上下文。)
  • 这里使用反射是为了避免在创建所需类型化 DataSet 的类型时进行切换。

    另一种方法是使用 ConstructorInfo 对象,该对象可以从 DataSetType 中提取以创建实例。 使用 ConstructorInfo.Invoke() 方法来完成此任务。

  • 非常欢迎任何建议、改进和错误报告。
© . All rights reserved.