12

I was wondering if my below implementation is the most efficient way to dispose the SQLconnection in this case.

I know normally if i'm using the SqlConnection directly I can just wrap the connection inside a using block to dispose it off automatically, but in this case i wanted to keep the connection open and available to All methods in the SQLRespository class.

public class SqlRepository : IRepository
{
    private readonly string connectionString;
    private SqlConnection connection;

    public SqlRepository(string connectionString)
    {
        this.connectionString = connectionString;
        connection = new SqlConnection(connectionString);
        connection.Open();
    }

    public void Method_A()
    {
      // uses the SqlConnection to fetch data
    }     

    public void Method_B()
    {
      // uses the SqlConnection to fetch data
    }     

    public void Dispose()
    {            
        connection.Dispose();
    }
}

Usage:

using (IRepository repository = new SqlRepository(connectionString))
{
   var item = repository.items;     
}

Update IRepository does implement IDisposable

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
newbie
  • 1,485
  • 2
  • 18
  • 43
  • Although its almost yes, but in case of an exception after opening a connection in using block, if your performing more operations then some exceptions throw will never dispose your connection object. And its not a good idea to make connection objects a global scope, instead play with CommandBehavior See here: http://stackoverflow.com/questions/7903326/why-does-my-successfully-read-npgsql-data-disappear/7903616#7903616 – Zenwalker Oct 27 '11 at 04:12
  • Another tip is, to please always adhere to guidelines and implement Dispose pattern. And connection.Dispose() will close the connection for you, you can check its IL and you shall see DBConnection.Close() being called. So opening conn under Using(){} is enough provided no exceptions are thrown. – Zenwalker Oct 27 '11 at 04:20
  • @zenwalker `...provided no exceptions are thrown` My understanding of a `using` statement is that it gets translated by the compiler into a `try`/`finally`, so it's always disposed of even in the case of an exception. – Joel C Mar 16 '12 at 14:23
  • [Improving Managed Code Performance](https://msdn.microsoft.com/en-us/library/ff647790.aspx) chapter of Microsoft patterns & practices has a number of relevant paragraphs. Search by the word `connection`. – Leonid Vasilev Jan 25 '18 at 14:59

3 Answers3

11

Don't keep the connection open spanning calls. You're defeating connection pooling.

If you're working with a connection that's pooled (like sqlserver), it will pool and reuse. Just open and close within method a & b.

You could argue that if the caller does what you did with using with one method call it's fine. But if you do using {} with sqlconnection inside each worker method (1) the code will be simpler and (2) you're ensured the pooling wont be defeated (meaning your holding items out of the pooling when other requests could use it).

EDIT:

Adding pseudo based on comments.

The pattern is problematic because a caller can do.

//pseudo code
using (SqlRepository r)
{
    r.MethodA();

    // other code here that takes some time.  your holding a connection
    // out of the pool and being selfish.  other threads could have
    // used your connection before you get a chance to use it again.

    r.MethodB();
}  // freed for others here.

That will kill the scalability of the server - trust me. I've seen very large systems get choked by this - usually because they're spanning AT side transactions.

A better pattern:

class Repository
{
    void MethodA()
    {
        using (Sqlconnection)
        {
             // db call
        }
    }

    void MethodB()
    {
        using (Sqlconnection)
        {
            // you can even have multiple calls here (roundtrips)
            // and start transactions.  although that can be problematic
            // for other reasons.  
        }
    }

Now, the pool is most effective. I realize the question was on the disposable pattern - and yes you can do it. But ...

I would not let the connection span the lifetime of the repository.

bryanmac
  • 38,941
  • 11
  • 91
  • 99
  • 1
    'maybe' - if you want transaction support then you may have a reason to keep it open. closed connections won't support a connection. Repositories sometimes will inject /construct another class (context, etc) that can be used over multiple repositories (with or without unit of work) – Adam Tuliper Oct 27 '11 at 04:16
  • Ok - would opt for transactions in SQL though. Holding the connection out of the pool blocking on a dtc tx might be a reason but that's got big drawbacks unless you absolutely have to. Point taken but I would be forced into that :) – bryanmac Oct 27 '11 at 04:28
  • Transactions are a cross cutting concern and imho don't belong on the sql side in general unless absolutely required. Code supports it for a reason, and the code should know what needs to be saved at once. If this goes on the sql server side, then you are determining to include logic on the db side which starts to get complicated when unit testing. my thoughts anyways : ) – Adam Tuliper Oct 27 '11 at 04:35
  • @bryanmac please see my comments below – newbie Oct 27 '11 at 07:00
  • @bryanmac if you plan to make more db calls then why close the connection, and if you don't plan to make more calls then the using block is closing the connection and putting it back to pool anyways. So I don't think it's a question of connection pooling especially since repository is of IDisposable type. – newbie Oct 27 '11 at 07:11
  • If you're going to make multiple calls back to back within a method then you can still wrap it with a using (connection){call1,call2). If you allow public methods to span an open connection, you will start to defeat pooling. I updated the answer to make it clearer why. – bryanmac Oct 27 '11 at 12:21
  • @bryanmac..just when i thought this was all figured out, i bump into an issue, if i open and close the connection within the method like you suggested, and my method returns an IEnumerable from a nested method which uses yield return, my connection goes out of scope and gets closed before the query can actually execute 'cuz of deffered execution by linq. Do i make sense? – newbie Oct 28 '11 at 05:31
  • I wouldn't defer execution. Once again, that keeps the connection scope at the mercy of the calling (and callers of those calling). Eventually, you have a server code base where it's tough to determine why sql resources are the bottleneck. I would get the results and get out. Treat sql as a precious resource (it is the bottleneck in a large system). You'll never notice these points on a smaller system. However, they are good habits and patterns for server development. – bryanmac Oct 28 '11 at 11:07
  • One other pattern is to try and avoid multiple round trips to sql - use sprocs, try to batch up your inputs and make 1 server call = 1 db round trip. That also avoids nested repo calls but may make the number of methods expand. Also, I'll admit haven't done Linq on server - mostly lower level ado.net ... This is all hard without concrete examples but patterns to strive for ... Hope it helps. – bryanmac Oct 28 '11 at 11:23
2

If you want to do it like that, ensure you implement IDisposable (I cant tell if you note this on your IRepository interface or not) and I'll do something like:


        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

Obviously the _context here is your SqlConnection.

however - are you sure you want one connection per repository? What about operations spanning more than one repository?

Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71
  • That's a better disposable pattern but the question is whether the connection should be held open across method calls when other requests could reuse that connection – bryanmac Oct 27 '11 at 04:22
  • I think you were hinting at that questioning 1 connection per repo ... Very bad if concurrent service – bryanmac Oct 27 '11 at 04:25
  • It absolutely depends on what you are doing. If your are not using a domain based unit of work (tracking models/objects and then submitting them), then you are left sharing a connection for this purpose if you need transactional support without hitting up the DTC service which requires this to be configured and running on a system - some choose not to. Some choose to handle this automatically, some choose unit of work, some choose sessions (nhibernate) or db/object contexts (EF) to handle this. The fact is though connections are still quite often passed around if the design calls for it. – Adam Tuliper Oct 27 '11 at 04:32
  • Above we have one connection per repository. If they are not using other patterns and need to share a connection, then as part of the design its required. – Adam Tuliper Oct 27 '11 at 04:32
  • Not sure what you exactly mean by spanning across repositories, I see the repository as one database, the repository is able to work with all entities defined for that database. I don't plan to have different repositories for let's say customer, order, product – newbie Oct 27 '11 at 07:03
  • Also I do understand your code but It's not quiet clear to me in what use case will i need to call Dispose(true)? Why not just the dispose I have defined in question? – newbie Oct 27 '11 at 07:05
  • It is typical that you have separate repositories (and separate ISomethingRepository : IRepository) representing your various entities otherwise everything is jammed into one large ugly object with a mess of an interface. Dispose(true) is the normal case. Dispose(false) is called internally by the runtime inside the finalizer. Note the pattern used at: http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize.aspx – Adam Tuliper Oct 27 '11 at 14:00
1

Assuming IRepository inherits from IDisposable, your implementation is fine provided you are not keeping an instance of your SqlRepository class open for longer than it takes to perform a 'logical' sequence of queries on the database. The fact that this sequence might span several method calls is not a problem.

I disagree with @bryanmac's answer:

Don't keep the connection open spanning calls. You're defeating connection pooling.

Provided your sequence of method calls belong together, and you don't keep the connection open for longer than it takes to complete the logical sequence, I don't see how this in any way defeats connection pooling.

One comment though. You should:

  • Either implement the standard IDisposable pattern (with a protected void Dispose(bool disposing) method that can be overridden in derived classes

  • Or make your class sealed, in which case your existing IDisposable implementation is fine.

Joe
  • 122,218
  • 32
  • 205
  • 338
  • It does implement IDisposable. I do somewhat agree with the connection pooling argument, when I wrap the repository usage within a code block I'm implying that the next bunch of methods are part of one logical transaction. Plus I like how looking at the code it's obvious that the repository will go out of scope outside the using block and hence all connections will be freed up. – newbie Oct 27 '11 at 06:59
  • By saying you'll avoid the pooling problem by wrapping consecutive calls in a using block - youre saying youll minimize the impact by always making the scope small and the calls back to back. Code will change over time - don't et your code ensure. Let the connection pool ensure connections are being used efficiently... – bryanmac Oct 27 '11 at 12:32
  • You're saying it won't be a problem "providing ..." and "as long as ...". the problem is you can say it won't be problematic as long as the callers of your repository do certain things. But why? what does the connection being scoped to the lifetime of your repository get you? It allows you to implement a cool disposable pattern and that's about it. If you scope the SqlConnection to each method, then the pool will ensure your *most* efficient because the use of each connection is granular. If you make a sequence of calls the pool will ensure you're good. – bryanmac Oct 28 '11 at 00:20
  • @bryanmac yes i guess sleeping over it i think differently today. You are right..why should the implementation be based around if's and "as long as..." – newbie Oct 28 '11 at 05:11
  • @bryanmac, I completely agree with you that it's better to keep a connection scope as small as possible, in general opening and closing it in each method that accesses the database. But if you do have a sequence of actions (e.g. in a transaction) that need to use the same connection, it's reasonable to put these actions in separate methods. – Joe Oct 28 '11 at 19:48