Click here to Skip to main content
Click here to Skip to main content
Go to top

How to improve performance of typed DataSet creation

, 23 May 2005
Rate this:
Please Sign up or sign in to vote.
How to improve performance of typed DataSet creation.

Introduction

A common object used to be passed in N-tier applications in .NET environment is a DataSet object. Moreover in order to ease the use of the DataSet object, we usually define it as a strongly typed DataSet (using XML schema).

A common scenario is to create (instantiate) the typed DataSet in one tier and then to pass it to the other tiers for further logic implementations. The creation of a typed DataSet is actually very expensive. I was amazed to realize (using various profiling tools) that around 15%-20% of my application was wasted on typed DataSets' ctors.

A proposed solution

Most of the applications use the following flow: a newly created DataSet is populated with data (either by the user or from the DB) updated with some logic, saved to DB and then finally discarded. The cycle then repeats itself.

(Refer the Remarks section for additional information of what can be done in cases where more than one instance of such a DataSet is needed.)

If the DataSet would be created only once, it would improve the performance significantly. Therefore the proposed solution is as follows: create once the desired typed DataSet, save it to a cache, and once needed, return it just after clearing its data using the DataSet.Clear() method. Is it essentially faster? Yes, I have tested it using various profilers and the DataSet.Clear() method is faster by 2-10 (!!!) times than a typed DataSet's ctor.

Below is the source code for a typed DataSet proxy which controls the creation of the desired typed 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.
                ...
            }
        }
    }
}

The client uses the typed DataSet proxy as follows:

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

    ...
}

Remarks

  • The proposed solution is not thread safe. If thread safety is an issue then a pool of typed DataSets can be used. (A pool of objects also solves cases where more than one typed DataSet object is needed.) A good article about managed pools of objects can be found here: Object Pooling with Managed Code - By Scott Sherer. (When thread safety is not an issue and still more than one typed DataSet object is needed, a simpler pool - without object context - can be used.)
  • Reflection is used here in order to avoid switching while creating the desired typed DataSet’s type.

    Another approach is to use the ConstructorInfo object which can be extracted from the DataSet’s Type in order to create the instance. Use ConstructorInfo.Invoke() method in order to accomplish the task.

  • Any suggestions, improvements and bug reports will be very much appreciated.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)

Share

About the Author

Uri Lavi
Other
Israel Israel
Uri Lavi is a development lead with extensive experience in Data Intensive, Business Compound, Distributed and Scalable Software Systems. Uri specializes in mentoring, coaching and consulting for complex software engineering topics, among which: Software Architecture, Design Patterns & Refactoring.

Comments and Discussions

 
GeneralWon't Work with Web Service PinmemberPaul Brower23-May-05 2:59 
GeneralRe: Won't Work with Web Service PinsussMuhammet TURŞAK23-May-05 9:56 
GeneralNo Problem PinmemberUri N.23-May-05 10:44 
GeneralRe: No Problem [modified] PinmemberCoşkun Aydınoğlu11-Aug-09 23:46 
GeneralGetNamespace PinsussAnonymous21-May-05 1:02 
GeneralRe: GetNamespace PinmemberUri N.21-May-05 3:08 
This solution contains a simple version of instance creation using reflection.
I have send an update to this article a few days ago (it wasn’t published yet) where I suggest another way to create instances using ConstructorInfo object that could be obtained from the typed DataSet’s Type.
About your last comment, refer to my Remarks section where I stated that if more than one instance of DataSet is needed then a pool of objects should be implemented.

GeneralGetNamespace PinsussAnonymous21-May-05 0:59 
GeneralMore performance data PinmemberDejan Grujic18-May-05 21:40 
GeneralRe: More performance data PinmemberUri N.19-May-05 5:41 
GeneralClear() performance PinmembermSerg17-May-05 22:06 
GeneralRe: Clear() performance PinmemberUri N.18-May-05 6:54 
GeneralUntyped DataSets Pinmemberscottctr13-May-05 10:40 
GeneralRe: Untyped DataSets PinmemberUri N.13-May-05 12:03 
GeneralRe: Untyped DataSets Pinmembermg_mchenry25-May-05 4:57 
GeneralRe: Untyped DataSets PinmemberUri N.25-May-05 7:36 
GeneralClone() vs Clear() PinsussJockeBocke13-May-05 3:21 
GeneralRe: Clone() vs Clear() PinmemberUri N.13-May-05 5:21 
GeneralRe: Clone() vs Clear() PinsussJockeBocke17-May-05 4:51 
GeneralRe: Clone() vs Clear() PinmemberUri N.17-May-05 6:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140905.1 | Last Updated 23 May 2005
Article Copyright 2005 by Uri Lavi
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid