Fog Creek Software
Discussion Board




Welcome! and rules

Joel on Software

maping tables to C# objects

Hello... I'm writing a news reader in C#, and I was wondering if I could get some feedback on the design I've chosen to use. 

I'm using a similar layout to Joel's entity classes, but I'm using structs and collections.  I have name/value collections mapping to most of the tables.  Internally when the collection is initialized, it selects all the IDs from the table.  Then, when I loop through it, it creates the individual struct for the row and grabs the row's data.

So, my code can look like this:

foreach(Item i in itemColl) {
  Console.WriteLine(i.Title);
}

It works out just fine, but I've noticed my app is a bit slower than other C# news readers.  When I click a category or site to view news items, I see a noticeable delay while it's filling the list view.  What possible optimizations could I do? 

I have thought of using DataSets, but I just thought that my simple structs and collections would be simpler...

I'm using MS Access right now, but may transfer to MSDE later on.  I'd love a way to support multiple DBs, possible using the database interfaces...

Thanks for any insight anyone can provide.

rick
Sunday, February 02, 2003

There's no magic to making code faster.  There are only FOUR  things you have to do:

1) Set "acceptable performance" goals, paying particular attention to goals that involve direct user interaction.  Like "when I click on a button something happens -- even if 'something' means getting an hourglass cursor -- within 200 milliseconds."

2) Build timing code into your application to measure what your actual time is compared to your acceptable time.  Make lots and lots of measurements.  Record them somewhere -- I usually use excel, or if I have huge amounts of data, Access.  (If you have a profiling tool, use it -- but you can get good data by putting timer checks right in the code.)

3) Find the worst unacceptably-slow thing and try to make it faster.  Measure again to see if it worked. If it didn't, try something else.

4) Repeat until there is nothing that is unacceptably slow.

Eric Lippert
Sunday, February 02, 2003

Rick, you sound surprised that your code is slower by grabbing the rows data individually, on demand, as you access each item. This shouldn't be surprising. More round trips to the database, with each involving a separate query==slower application.

DataSets won't make your application faster on their own. DataSets are normally used to store the entire results of some query *in one go*. If you implemented your solution similarly (ie, stored more that just the IDs when you initialised the collection) they would be of comparable speed.

Any particular reason you're using structs? They don't seem the right approach for storing in a collection especially, as they would need to be "boxed" to be stored there anyway.

MS Access is lightning fast as it is (for small databases (<2GB?), with few users(<10?)) - switching to MSDE is not going to make it go any faster.

HTH

Duncan Smart
Monday, February 03, 2003

First, I'm using structs because they seemed simpler to use.  Yes I do have to box them in the collection, but don't I have to box classes as well?

Anyways, I set up a little profiler and saw that it takes anywhere from 500-900 milliseconds to fill up a listview with about 40-60 items.  I added the necessary constructors to my classes to fill them up with one big query and I'll time it again. 

At first, my collections worked like this:

1. Select IDs, fill an arraylist with them.
2. the enumerator gets each value from the arraylist, and creates an item object
3. the item object loads the rest of the data from the database

With the new constructors, I'll restructure it like this:
1. select all the data
2. fill the item objects with the data, add them to an array list
3. the enumerator returns each object from the arraylist

I'll see if this approach yields better results.

rick
Monday, February 03, 2003

Silly me, the Item Collection works differently than all the other objects I created.  It already loaded the whole object in the collection.  I created a quick profiling class, and it looks like the db access isn't the slow part.  I found some articles on .Net performance and profiling that I'm going to read to see if I can figure something out...

rick
Monday, February 03, 2003

> "but don't I have to box classes as well?"

No: to clarify, "boxing" occurs whenever you store a System.ValueType (int, DateTime or any custom struct) in a variable of type System.Object -- which is what most collections do. Basically a copy is made of the instance and stored in the object "box". With classes though, being Reference types, no copying occurs, just the reference to the existing instance is stored in the collection.

Bottom line: stick with classes, only use structs wherever you need "x = y" to perform a copy (which is not all that often).

Duncan Smart
Tuesday, February 04, 2003

DB access screams these days.  So, you should get the data you need when you need it.

If that doesn't perform well enough, try caching.  If you are using a Factory method to get at the data, then this should be invisible to your clients. 

But, be careful when designing your cache.  You will need to deal with concurrency and accuracy.  I'd look for a comercial solution if you haven't done any caching before.

HTH.

David Lanouette
Sunday, February 09, 2003

*  Recent Topics

*  Fog Creek Home