Updating the Database Wrapper for C#

by Sameera 19. June 2008 04:52

I have made a few updates for my Generic Database Wrapper class. The update contains a bug fix along with several additional methods for supporting DbParameters.

The new source file can be downloaded here. I have also updated the file linked to the original post.

My Favorite Database Wrapper for C#

by Sameera 7. November 2007 19:28

As a guy who started programming back in the days of DAO, I have nothing but love for ADO.NET. But let's face it, you can still end up writing pretty lousy code with it. Not everybody's fully aware of the best uses of the ADO.NET. One of the most common problems I keep stumbling onto in other peoples code is the poor use of ADO.NET Connection Pooling feature.

Somewhere, down the line Microsoft probably started noticing that their cool new data access model wasn't being fully utilized. The birth of the Microsoft Enterprise Library was probably due to this.

As cool as the Enterprise Library is, I've found it to be an over kill for most of my projects. In fact one of my favorite projects featured on CodeProject, was because Enterprise Library's Offline Application Block was so clunky (and very limited).

Around the same time that I worked on on the SCOAB (Smart Client Offline Application Block), I also wrote a ADO.NET wrapper similar to the Enterprise Library. It pretty much follows the public interface of the Enterprise Library, but it's a very tiny wrapper compared to the enormous DAAB (Data Access Application Block).

You can download the .cs file here: AbstractDatabase.zip (1.88 kb)

This contains a generic abstract base class called AbstractDatabase. You can extend this class to use it with any type of relational database type. If you take a look at my SQLite Membership Provider, you'll find this class derived to be used with SQLite ADO.NET Wrapper. I have simply called that class Database, and it's code looks something like this:


public class Database : AbstractDatabase<SQLiteConnection, SQLiteCommand, SQLiteDataAdapter>
{
    protected override string  GetConnectionString()
    {
        return string.Format(ConfigurationManager.ConnectionStrings["BlogEngine"].ConnectionString,
                            HttpContext.Current.Server.MapPath("~/App_Data"));
    }
}

As you see, the only member you need to override is the GetConnectionString() method. This brings up the question as to why I made this abstract. Why not read the connection string value from the web.config? Well, I've done this because I use this class on both web and desktop projects. And in some cases, especially with WinForms applications, the database is SQLite and resides in the application directory. When that happens, I can always hard code the database file name.

Here's a example of the the Database class's usage (taken from the SQLiteBlogProvier class).


using (Database db = new Database())
    using (DbTransaction txn = db.BeginTransaction())
    {
        DbCommand cmd = db.GetSqlStringCommand("DELETE FROM be_Settings"); // SQLite doesn't support TRUNCATE
        db.ExecuteNonQuery(cmd, txn);

        cmd = db.GetSqlStringCommand(
            "INSERT INTO be_Settings (SettingName, SettingValue) VALUES (@name, @value)");
        db.AddInParameter(cmd, "@name", DbType.String, "");
        db.AddInParameter(cmd, "@value", DbType.String, "");
        foreach (string key in settings.Keys)
        {
            cmd.Parameters[0].Value = key;
            cmd.Parameters[1].Value = settings[key];
            cmd.ExecuteNonQuery();
        }
        txn.Commit();
    }

A quick rundown of the public interface of AbstractDatabase class:


void AddInParameter(System.Data.Common.DbCommand, string, System.Data.DbType, object)
void AddInParameter(System.Data.Common.DbCommand, string, System.Data.DbType, int, object)
DbTransaction BeginTransaction()
void Dispose()
DataSet ExecuteDataSet(System.Data.Common.DbCommand)
int ExecuteNonQuery(System.Data.Common.DbCommand)
ExecuteNonQuery(System.Data.Common.DbCommand, System.Data.Common.DbTransaction)
DbReader ExecuteReader(System.Data.Common.DbCommand)
ExecuteReader(System.Data.Common.DbCommand, System.Data.CommandBehavior)
T ExecuteScalar<T>(System.Data.Common.DbCommand, T)
abstract string GetConnectionString()
DbCommand GetSqlStringCommand(string)
DbCommand GetSqlStringCommand(string, params object[])
DbCommand GetStoredProcedureCommand(string)
Connection { get; }

Update (June 20, 2008): I have updated this class with a minor bug fix and have added support for other parmeter types including Output and InputOuput parameters (Thanks Yordan).

Update (Oct 20, 2008): This wrapper has been updated and made a part of the Codoxide Common Library

Proud owner of {smartassembly}

by Sameera 7. November 2007 07:34

This is just a note to say {smartassembly} (Professional Edition) has entered my development toolbox.

It all began with DotFuscator Community Edition flatly refusing to obfuscate our VSTO application. That got me searching for an affordable alternative. A good resources that I came across during the research is the How to Select Guide for .NET Obfuscators.

The article has since been updated and few of the obfuscators has been removed for some reason. However, the page led me to few products (including couple of free ones). These include,

  • Aspose.Obfuscator
  • Salamander .NET
  • Spices.Obfuscator
  • {SmartAssembly}
  • .NET Reactor
  • Skater.NET

Aspose and Skater did a blind obfuscation of the VSTO add in which ended up breaking the application. After bit of evaluating, I narrowed down the selection to .NET Reactor and {SmartAssembly}. The Reactor was cheaper and as a bonus contained an additional licensing library. Having already purchased a licensing component from  a different vendor,  this wasn't much of a selling point for us. However, at almost half the price of {SmartAssembly}, Reactor still was a good enough option.

{SmartAssembly} on the other hand came with a host of more valuable features including assembly optimization, merging, pruning and (get this) automated unhandled exception reporting. But, being the only developer who's charged with using the obfuscation tool, I had to discipline myself and get only what I need, nothing more. So the scales were tilting towards the Reactor at this point.

Then came an important consideration: how good is their customer support. From one of our previous purchases we had learned that sometimes this makes a huge difference. We had evaluated a product based on a limited set of requirements. The product handled these requirements well enough, and the price was about 10% of what the competitors were offering.

Few months after the purchase our requirements changed, requiring the product to handle an entirely different scenario. Theoretically, it had the required features to pull it off.  But, when it was actually put to the test, the product started to crumble. It was only after several weeks of frustrating email exchanges, bug reports and personally hacking some changes into their source code that I finally managed to make it work. Luckily for us, the developers of the product were quite responsive and did everything they could to get the necessary fixes out. I hate to imagine what would have happened otherwise.

So here's how I nailed down that Reactor was a risk and that {SmartAssembly} was the one to get:

Step 1:

Search Google for: <product name> review
.NET Reactor will return 195,000 results.
{SmartAssembly} returns 2,480 results.

But that's a worthless statistic. What you should look for are the sources of the link. You can browse through the multitude of results for Reactor and find that almost every single one of them are from 3rd party software download sites. The "review" they contain is only a repetition of the vendor's exact words.

Contrastingly, majority of the top hits for {SmartAssembly} are from some reputed blogs or developer resources sites (e.g. weblogs.asp.net, 4guysfromrolla). A simple search for {SmartAssembly} will also show you that it's been featured in the Scott Henselman's privileged list of Ultimate Developer tools.

Step 2:

Go to the vendor's online contact form and ask a simple question about the product or a feature. {SmartAssembly} got back to me on the very same day. I'm yet to hear from the Reactor guys :)

The point here is if they don't talk to you when you need to make up your mind about buying their product, they won't talk to you when you are stuck with a problem after paying.

So now, I have my copy of {SmartAssembly} to play with. I'm yet to put the product to it's full use, having only concerned myself with the obfuscation part of it. You can bet that there'll be more posts on this subjects in the coming weeks.

On a completely unrelated topic (related only in that it's something you should be aware of when purchasing over the Internet), take a look at the article on Software Awards Scam.

SOAB is good to go!

by Sameera 19. March 2006 09:57

Yes, it’s done. I’ve finished putting the finishing touches on the smart client offline application block. All that remains is to figure out a cool name for the project. In any case, I’d post the code and a demo application at Codeproject.com tonight. In the meantime, here’s some of the paper work I finished.

Benefits of the new SOAB

  • Simplified Deployment
    No SQL Servers to deploy, no database scripts to run, no logins to create; simply application where you want and run it. The cache and queue databases will be created on the fly the very first time it’s needed. It’s that simple!
  • Inter-dependant queue elements
    Imagine a smart-client application used for cataloging books. The central server maintains a catalog of book and authors. For a book to be cataloged, its author must exist in the database. (Exactly how such an application would be useful is of no concern to us here :). The smart client downloads the list of authors from the server when it goes online. A problem arises when a book along with its author has to be created offline. When an author is created offline a “Create Author” request is queued in the command queue. Likewise, when a book is created a “Create Book” request is queued. The new SOAB provides a mechanism by which the programmer of the smart-client could specify that a “Create Book” request should be executed (transferred to the web-service), only once its related author object has been successfully put on the central database.
  • All the glory of Db4O
    Db4O is a powerful Object Database, with advanced functionality such as native query, SODA query, etc. etc. While the SOAB.Data.Database class attempts to wrap most of the interactions with the underlying Db4O Object Container, it is still accessible to the brave-hearted. This opens up number of additional possibilities such as modifying/deleting individual items from the queue, querying for specific items in the cache or the queue, determining which items are to be modified when the queued elements are executed etc.
  • Tiny Code base, built on .NET 2.0
    The application block has only about 15 classes and interfaces in total: Out of which only 6 you’d need to concern yourselves with. You’d probably take less than 2 hours to identify how to harness the full potential of the SOAB. The new SOAB uses generics, and the new event-based asynchronous invocation methods, breaking away from the old way of doing things.

Working with the SOAB

Working with the SOAB is almost effortless; simply follow these few steps

  • In your smart-client application, add a class derived from SOAB.ServiceAgent. In the sample application I have made this derived class (ServiceClient) a singleton. While this is not always required, it might be a good idea to do so.
  • Create a ServiceContext class and keep it around as it can be used for all service requests. Since, the ServiceClient is a singleton, I’ve made the ServiceContext instance, on of its fields. The ServiceContext class is basically a builder for your web-service proxy class. Make sure that you pass the fully qualified class name of the proxy to its constructor.
  • When you need to invoke a web method, create and populate a ServiceRequest object and enqueue it using QueueManager.Instance.Enqueue(…) method. To populate the ServiceRequest assign;
  • The ServiceContext instance to the ServiceRequest.ServiceContext property.
  • The name of the web-method you are invoking to ServiceRequest.RemoteMethodName.
  • The argument to the web-method to ServiceRequest.Payload.
  • The name of a method accepting a ServiceResponse argument belonging to the ServiceAgent derived class to ServiceRequest.CallbackMethodName.

The method specified in the CallbackMethodName property, is invoked once the ServiceRequest has been executed. You should use the properties in the ServiceResponse object passed on to the method to determine whether the request was successful, cancelled or whether it generated an exception. If you have any object types that might depend on other objects (such as Book that depend on Author), you should implement ICacheDependant interface on the dependant class. Provide the dependency resolution logic in the IsResolved property-getter and return true if the object is ready to be transferred to the web method.

Words to the Wise

Please note that this is my first complete project using Db4O. So, the Db4O-related code might not be optimal. For instance, I’ve used ReaderWriterLocks for guarding object container read/write actions. However, the database itself has built in locking mechanisms which I could’ve used for the same purpose. Hopefully, somebody who’s more experience with Db4o can offer some assistance …?

About Me

Sameera Perera

Sameera Perera

  • Solutions Architect
  • View Sameera Perera's profile on LinkedIn

Calendar

<<  September 2010  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar

Disclaimer

This is a personal blog. The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

All forms of source code published on Codoxide.com are distributed under the Apache License, Version 2.0 unless otherwise stated.
The rest of the content are published under a Creative Commons Attribution 3.0 License.
Creative Commons License