Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C#
Article

How to improve performance of typed DataSet creation

Rate me:
Please Sign up or sign in to vote.
4.22/5 (14 votes)
23 May 2005CDDL2 min read 121.7K   693   36   19
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.

C#
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:

C#
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)


Written By
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 Pin
Paul Brower23-May-05 2:59
Paul Brower23-May-05 2:59 
GeneralRe: Won't Work with Web Service Pin
Muhammet TURŞAK23-May-05 9:56
sussMuhammet TURŞAK23-May-05 9:56 
GeneralNo Problem Pin
Uri Lavi23-May-05 10:44
Uri Lavi23-May-05 10:44 
GeneralRe: No Problem [modified] Pin
Coşkun Aydınoğlu11-Aug-09 23:46
Coşkun Aydınoğlu11-Aug-09 23:46 
GeneralGetNamespace Pin
Anonymous21-May-05 1:02
Anonymous21-May-05 1:02 
GeneralRe: GetNamespace Pin
Uri Lavi21-May-05 3:08
Uri Lavi21-May-05 3:08 
GeneralGetNamespace Pin
Anonymous21-May-05 0:59
Anonymous21-May-05 0:59 
GeneralMore performance data Pin
Dejan Grujic18-May-05 21:40
Dejan Grujic18-May-05 21:40 
GeneralRe: More performance data Pin
Uri Lavi19-May-05 5:41
Uri Lavi19-May-05 5:41 
When using a "simple" typed DataSet (1-3 tables) the difference is small, but when the typed DataSet grows (5-10 tables (30+ columns) with relations and etc ...) the difference is much more significant.
As I have stated in the article I came across 15%-20% of performance hit only because of the typed DataSet’s ctor.
(BTW. your article is great!)
GeneralClear() performance Pin
mSerg17-May-05 22:06
mSerg17-May-05 22:06 
GeneralRe: Clear() performance Pin
Uri Lavi18-May-05 6:54
Uri Lavi18-May-05 6:54 
GeneralUntyped DataSets Pin
scottctr13-May-05 10:40
scottctr13-May-05 10:40 
GeneralRe: Untyped DataSets Pin
Uri Lavi13-May-05 12:03
Uri Lavi13-May-05 12:03 
GeneralRe: Untyped DataSets Pin
mg_mchenry25-May-05 4:57
mg_mchenry25-May-05 4:57 
GeneralRe: Untyped DataSets Pin
Uri Lavi25-May-05 7:36
Uri Lavi25-May-05 7:36 
GeneralClone() vs Clear() Pin
JockeBocke13-May-05 3:21
sussJockeBocke13-May-05 3:21 
GeneralRe: Clone() vs Clear() Pin
Uri Lavi13-May-05 5:21
Uri Lavi13-May-05 5:21 
GeneralRe: Clone() vs Clear() Pin
JockeBocke17-May-05 4:51
sussJockeBocke17-May-05 4:51 
GeneralRe: Clone() vs Clear() Pin
Uri Lavi17-May-05 6:39
Uri Lavi17-May-05 6:39 

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

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