I always had this feeling that POCO (Plain old C# objects) will outperform typed datasets & datasets. The main reason why people are using it is only because it lessen development time by a very....... small amount in my opinion. Using business objects are easier to understand and in C# context, the compiler actually do a lot of work for you.
Example in other languages:
public myClass()
{
private String someString;
public String getString()
{
return this.someString;
}
public void setString(String value)
{
this.someString = value;
}
}
you can do this in C#:
public myClass()
{
public String someString { get; set; }
}
That only explains how much it takes to write a Business Object class. Next we go to
real work.
I created a simple demo project in VS 2010 (beta), you can use any visual studio to compile this if you want to try it out yourself.
in my Business object class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DemoBizObject
{
public class BizObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Desc { get; set; }
public decimal price { get; set; }
public DateTime CreatedDt { get; set; }
public DateTime ModifiedDt { get; set; }
}
}
in my aspx code behind, i did this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections.ObjectModel;
using DemoBizObject;
using System.Diagnostics;
using System.Web.UI.DataVisualization.Charting;
namespace DemoWebApp
{
public partial class _Default : System.Web.UI.Page
{
Collection<BizObject> BizObjects = new Collection<BizObject>();
double[] pocotimings = new double[7];
double[] typeddstimings = new double[7];
decimal d = 0.00m;
const int ONE = 1;
const int TEN = 10;
const int ONEHUNDRED = 100;
const int ONETHOUSAND = 1000;
const int TENTHOUSAND = 10000;
const int ONEHUNDREDTHOUSAND = 100000;
const int ONEMILLION = 1000000;
const string LINEBREAK = "<br />";
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
this.Label1.Text += "Typed Datasets" + LINEBREAK + LINEBREAK;
this.Label1.Text += ONE +": "+ demoTypedDS(ONE)+ LINEBREAK;
this.Label1.Text += TEN + ": " + demoTypedDS(TEN) + LINEBREAK;
this.Label1.Text += ONEHUNDRED + ": " + demoTypedDS(ONEHUNDRED) + LINEBREAK;
this.Label1.Text += ONETHOUSAND + ": " + demoTypedDS(ONETHOUSAND) + LINEBREAK;
this.Label1.Text += TENTHOUSAND + ": " + demoTypedDS(TENTHOUSAND) + LINEBREAK;
this.Label1.Text += ONEHUNDREDTHOUSAND + ": " + demoTypedDS(ONEHUNDREDTHOUSAND) + LINEBREAK;
this.Label1.Text += ONEMILLION + ": " + demoTypedDS(ONEMILLION) + LINEBREAK + LINEBREAK;
this.Label1.Text += "POCO" + ": " + LINEBREAK + LINEBREAK;
this.Label1.Text += ONE + ": " + demoPOCO(ONE) + LINEBREAK;
this.Label1.Text += TEN + ": " + demoPOCO(TEN) + LINEBREAK;
this.Label1.Text += ONEHUNDRED + ": " + demoPOCO(ONEHUNDRED) + LINEBREAK;
this.Label1.Text += ONETHOUSAND + ": " + demoPOCO(ONETHOUSAND) + LINEBREAK;
this.Label1.Text += TENTHOUSAND + ": " + demoPOCO(TENTHOUSAND) + LINEBREAK;
this.Label1.Text += ONEHUNDREDTHOUSAND + ": " + demoPOCO(ONEHUNDREDTHOUSAND) + LINEBREAK;
this.Label1.Text += ONEMILLION + ": " + demoPOCO(ONEMILLION) + LINEBREAK + LINEBREAK;
}
private string demoTypedDS(int numOfRecords)
{
typedDS ds = new typedDS();
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < numOfRecords; i++)
{
ds.DemoTable.AddDemoTableRow(i, "demo name", "demo desc", d + i, DateTime.Now, DateTime.Now);
}
watch.Stop();
return watch.Elapsed.TotalSeconds.ToString();
}
private string demoPOCO(int numOfRecords)
{
BizObject tempObject;
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < numOfRecords; i++)
{
tempObject = new BizObject();
tempObject.Id = i;
tempObject.Name = "demo name";
tempObject.price = d + i;
tempObject.CreatedDt = DateTime.Now;
tempObject.ModifiedDt = DateTime.Now;
tempObject.Desc = "demo desc";
BizObjects.Add(tempObject);
}
watch.Stop();
return watch.Elapsed.TotalSeconds.ToString();
}
}
}
pardon my messy codes, i didn't want to create this project initially, but i want to be someone that talks the talk
and walk the walk.Next, create a similar table in your database with following...
After that, right click on your solution file and click "Add new item" and select a dataset object.
Double click on the XSD file and go to your DB and drag-and-drop the table onto the XSD and you will get the table there..
The codes are very self explanatory and simple, not much re-using of codes especially @ the printing part.
I ran the test and get the results for POCO VS DS
Results are:
Typed Datasets
1: 4.1E-05
10: 5.47E-05
100: 0.0004515
1000: 0.0045912
10000: 0.0747852
100000: 0.6806366
1000000: 7.4931112
POCO:
1: 5.8E-06
10: 9.6E-06
100: 8.26E-05
1000: 0.0008128
10000: 0.0081756
100000: 0.1015654
1000000: 1.1922586
I tested it several times and dare to confirm that with this demo project, POCO is that Datasets in the lower range (1 to thousands) and the ratio justs exponential when the records reaches millions.
In this test, i only did instantiation and assignment, the Big O notation for:
- POCO = n Log n
- Dataset = C^n
I don't find the need to extract data from database tables and going through the whole cycle as it will end up the same for both, the main difference only occurs when i instantiate and assign values to them. Even with just 6 primitive type objects, typed datasets are giving C^n in terms of performance. That is why my organization's Entity Objects are such a pain in the neck (they used typed datasets
plus overriding several events)