19

I have created an singleton class, this class returns a database connection. So my question is this connection is also satisfying singleton criteria?
If no, than how I can make it singleton.
Here is the code.

public sealed class SingletonDB
{
    static readonly SingletonDB instance = new SingletonDB();
    static SqlConnection con =new SqlConnection(ConfigurationManager.ConnectionStrings["mydb"].ConnectionString);

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static SingletonDB()
    {
    }

    SingletonDB()
    {
    }

    public static SingletonDB Instance
    {
        get
        {
            return instance;
        }
    }

    public static SqlConnection GetDBConnection()
    {
        return con;
    }
}
2
  • 1
    code updated, now comment on new code Commented May 2, 2009 at 10:03
  • have you thought about injecting the SQLConnection dependency to your singleton class? Commented Jul 9, 2011 at 21:33

7 Answers 7

44

Your Singleton is still off.

As far as the singleton pattern goes, please see Jon Skeet's very good and detailed description here : http://www.yoda.arachsys.com/csharp/singleton.html

Using a Singleton for a SqlConnection object is a really, really bad idea. There is no reason to do this whatsoever.

If you are attempting to avoid a performance hit of "new SqlConnection()" or "connection.Open()" be advised that there really is no performance hit there because of the connection pooling going on behind the scenes. Connection Pooling handles the opening/closing of the expensive connections. Not the SqlConnection object.

You won't be able to open multiple SqlDataReaders/Commands with the connection at the same time and will run into thread blocking issues if you are trying to share the same connection object with multiple threads.

The Singleton pattern is the most over used and abused pattern and there are many side effects of the singleton that you may not be aware of. Very good talk about the dangers of singletons here http://www.youtube.com/watch?v=-FRm3VPhseI

Sign up to request clarification or add additional context in comments.

5 Comments

All my life I've been trick with don't make a connection on every call because "it's kill the application performance".
A link to updated Jon Skeet's article on singleton pattern can come in handy.
what about command =MySqlCommand()? Is it good, when be used through Singleton?
@Corio I've proposed an edit to the answer to change the link to the one you referenced.
This answer is generally not correct. There are indeed situations where you have to work with Singletons. And a question was asked where this is not an answer. The question was not whether it is good to use singletons - but how the ConnectionString gets to the singleton.
5

In .NET C# you can wrtie your singleton like this

    public class Singleton{
public static readonly Singleton Instance= new Singleton();
private Singleton(){}

or for multi threaded environment:

using System;

public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }

         return instance;
      }
   }
}

1 Comment

Please see this MSDN Page for more info: msdn.microsoft.com/en-us/library/ff650316.aspx
4

The connection itself is not satisfying the Singleton criteria because you can create multiple instances of a database connection object. A singleton by definition can only be instantiated once.

You can make the SqlConnection a part of the Singleton, by changing your example to this:

public sealed class SingletonDB
{
    private static readonly SingletonDB instance = new SingletonDB();
    private readonly SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["mydb"].ConnectionString);

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static SingletonDB()
    {
    }

    private SingletonDB()
    {
    }

    public static SingletonDB Instance
    {
        get
        {
            return instance;
        }
    }

    public SqlConnection GetDBConnection()
    {
        return con;
    }
}

This way the SqlConnection used by your SingletonDB class would have one and only one SqlConnection, thus follow the Singleton pattern.

Comments

2

Singleton means that the class that you have made can be instantiated only once. So if you want that to happen, do two things:

  1. Make the constructor private.(This is to prevent other classes from accessing it.)
  2. instantiate the class as:

    get
    {
     if(instance == null) //important coz, the class will be instantiated only on the first call
     {
       instance = new singletonDb;
     }
     return instance;
    }
    

Comments

1

If there's no other way to get a connection to the DB, and if this attribute cannot be overwritten, I would say yes. If that's what you're doing, you're probably taking this singleton thing too far. What if the the DB goes down temporarily and your app loses its connection? Then you'll have to restart your app in order for it to be able to use the DB again.

Comments

1

I can't answer that question without seeing some code, I think. If you are saying that you will have only one DB connection instance in your application, that might work if you can guarantee that your application will run on only one thread (or at least that all operations using the DB connection does), since you can't (as far as I know anyway) run several operations in parallell on the same connection.

Also, if it means that your application will keep the connection open in between uses, I would advise against it. DB connections are limited resources on the DB server, so you should keep them open only when they are needed, and then close them.

Comments

0

You don't have to discard the idea of a singleton just because it will need an IDbConnection. You can solve the problem similarly to how efcore does with its IDbContextFactory.

Rather than using IDbConnection directly, you use a wrapper class around a function that will create an IDbConnection on the fly instead.

public class DbConnectionFactory
{
    private readonly Func<IDbConnection> _connectionCreator;

    public DbConnectionFactory(Func<IDbConnection> connectionCreator)
    {
        _connectionCreator = connectionCreator;
    }

    public IDbConnection CreateConnection()
    {
        return _connectionCreator();
    }
}

You can create an extension method to add it to services, if you'd like.

    public static IServiceCollection AddDbConnectionFactory(
        this IServiceCollection collection,
        Func<IDbConnection> connectionCreator
    )
    {
        return collection.AddSingleton(new DbConnectionFactory(connectionCreator));
    }

Then in your Startup.cs, add it to your services.

//services.AddTransient<IDbConnection>(db => new Microsoft.Data.SqlClient.SqlConnection(connectionString));
services.AddDbConnectionFactory(() => new Microsoft.Data.SqlClient.SqlConnection(connectionString));

Let's say you want a singleton that's supposed to ReadData on command.

services.AddSingleton<MySingleton>();

If your class looks something like this...

public class MySingleton(){

  private readonly IDbConnection _connection;

  public MySingleton(IDbConnection connection){
    _connection = connection;
  }

  public void ReadData(){
    var command = _connection.CreateCommand();
    //...
  }

}

change it to this...

public class MySingleton(){

  private readonly DbConnectionFactory _connectionFactory;

  public MySingleton(DbConnectionFactory connectionFactory){
    _connectionFactory = connectionFactory;
  }

  public void ReadData(){
    using var connection = _connectionFactory.CreateConnection();
    var command = connection.CreateCommand();
    //...
  }
}

Now you are opening and disposing a connection every time you call ReadData(), rather than using a connection that tries and fails to stay open.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.