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 DataSet
s' 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
{
public class DSProxy
{
private const int InitialCacheSize = 2;
private Hashtable cache;
private static DSProxy DSProxyInstance;
private DSProxy()
{
cache = new Hashtable(InitialCacheSize);
}
public static DSProxy Instance()
{
if(DSProxyInstance == null)
DSProxyInstance = new DSProxy();
return DSProxyInstance;
}
private string GetNamespace(string dsType)
{
try
{
return dsType.Substring(0, dsType.IndexOf("."));
}
catch(Exception e)
{
...
}
}
public DataSet GetDS(string dsType)
{
try
{
DataSet ds;
if(cache[dsType] == null)
{
Assembly asm = Assembly.Load(GetNamespace(dsType));
ds = (DataSet)asm.CreateInstance(dsType, true);
cache.Add(dsType, ds);
}
else
{
ds = (DataSet)cache[dsType];
ds.Clear();
}
return ds;
}
catch(Exception e)
{
...
}
}
}
}
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