November 2007


I posted last night before midnite here but it registered as posting this morning..

 That is so bizarre.   It turns out the “time” setting for my blog was off by an hour so if I posted after 11pm it appeared on the next day.

 So I still posted 1 per day this month!

Does it concern people that the cost of a college education is rising faster than inflation?  (and by a lot).  My children are 6 and almost 4 and I wonder a lot about what it’s going to cost for them to go to college (don’t even get me started on the cost of weddings ;) ).  I’d love to be able to save money for them to goto a good college but the reality is that at today’s rate of increase it’s an uphill battle to save.  The frustrating part is that I make a pretty decent living, yet if I want to save for their college I have to sacrifice the present and potentially what I’ll have available when I retire. 

I’m not sure what to think about this and am struggling with it a lot.  On the one hand, I got scholarships and financial aid.  In all I ended up paying for about 1 year of my education, and my parents paid for about a year.  Is that a more realistic expectation of what I should plan for?

 How do you budget for your children’s education (if at all)?

One of my favorite christmas shows is on tonite… I don’t know why but I really enjoyed the Grinch christmas special growing up.  It was a lot of fun the way the words and songs just kept rhyming and grabbing at my attention.  I truly enjoy that show.  We are Recording it tonite (along with the Shrek special) for the kids to enjoy :)

Apparently there is this website out there where you can register and when you shop online at certain places (some well known), a donation is given to the fund you “associate” your account with.  It sounds pretty interesting. If you shop online maybe igive is something you might want to look into.  (although I’m not sure if the prices are the “absolute best” you can do.)  So there is a reason I’m talking about Igive… 

My sister-in-law’s husband was recently diagnosed with Cancer of the esophagus and it has now metastasized in the liver.  The prognosis is not good.  Tony Hurd is 40 years old, he’s mentally and physically handicapped, and the health insurance he has available to him, frankly, sucks.  Tony can no longer work so the little money that he was bringing in is not coming in at all.  They have to fight through all kinds of red tape to attempt to get better health care.  Tony’s family is trying hard to get him the best care they can but they need help, so they’ve registered at igive.com under the “Tony Hurd cancer fund.” 

Rough fall over here…

We had a consultant into work today… His name is Dan Sullivan (author of a number of SQL Server books).  It was a super productive day.  We spent time going over our database specifically looking at indices and how they impact (both positively and negatively).  I guess I never really thought about how indexing works in a database, but it’s pretty cool.  One of the more important things we learned is… “DON’T blindly follow the Database tuning advisor’s recommendations.”  While the tuning advisor might suggest an index, it doesn’t know a lot about your data in the database so it makes suggestions on indices that don’t always make sense (ie if you have an int as a column that can only have 3 values… it probably doesn’t need to be included in the key). 

Anyway.  Tomorrow I should be breakingout the batching code I talked about last week.

The Patriots are just amazing to watch this season.  It’s interested to see how bad (or is it just “equal”) the rest of the league is… I mean the pats game just started and the defense scored a touchdown in less than 2 minutes.  The offense hasn’t even been on the field yet

Well I’ve been trying (and succeeding) to create a blog post each day for the month of November.  And I’ve been succeeding.  This is very cool for me.  What I need to do now though is start figuring out how to make more substantial posts, or keep track of my ideas better.  I find it hard as I’ve always go things bouncing around in my head and lots of things I want to talk about and I forget a lot of em before I get to write them down.  James over at Aces Full of Links has the trick down it seems.  Go James!

My hope is that I can keep up the pace of blogging (maybe not a post per day) when this month is over.  I’ve been doing a lot of learning lately and hope that I can share some of what I’ve done (Ruby on Rails, Linux, Drupal etc).   I also owe you my database batching code.  Which will be up for tomorrow’s post :)   I’ve almost got it done :D

Also when this month is over I think I’ll be chaning over to new blog software, and hosting it from my own machine.

I think I ate too much yesterday :) .  Anyway, I spent the afternoon in a pool with my kids today.  We visited our friends the swindells up in NH.  They were staying at steele hill resorts just outside of Tilton.  They were thinking about time shares (they met with a sales guy).  From the sounds of things time shares seem overly complex.  I just don’t get em :) .

I give thanks every day for my friends and family.  Without you/them life would be a whole lot harder.  You make the good times better and the hard times easier.  I especially would like to thank my wife for being my friend and companion, and for always being there for me.

So I created the Database batching code that I spoke about recently and the way I went about doing it was to create the unit tests first.  And then get the code to work.   My goal from the beginning was 100% code coverage of all my unit tests.  So using NCover and NUnit and NMock I was able to achieve that.  Then when I replaced the existing database access code with my new code.   ALL the preexisting DB access unit tests passed (we have some unit tests that work with the database) in one try!  WOOOTT!!!  And at the same time a coworker of mine changed some of his code, didn’t even run the existing unit tests and checked his code in and he broke the build for 5 hrs.  I had to wait that 5 hours before I could check my code in.

Here are my unit tests, the class in question that I am testing is the database executor class (called Database in this version). If you are interested in seeing the DB execution implementation post here and I’ll put it up in my next post. (I’d like to see if people are actually interested in this series of articles :) )

[TestFixture]
public class DatabaseAccessingTestFixture
{
    private List myConnectionStrings;
    [SetUp]
    protected virtual void SetUp()
    {
        myConnectionStrings = new List();
        myConnectionStrings.Add("Blah!");

    }

    [Test]
    public void SingletonAccessShouldReturnDatabaseObject()
    {
        Single.Instance = null;
        Assert.IsInstanceOfType(typeof(Database), Database.Instance);
    }

    [Test]
    public void ExecuteSingleCommandShouldOpenANewConnectionAndExecuteTheCommand()
    {
        Mockery mocks = new Mockery();
        IDbCommand cmd = mocks.NewMock();
        IDbConnection con = mocks.NewMock();
        IDataReader rdr = mocks.NewMock();

        Database db = new Database();
        int workCalled = 0;
        DataReaderConsumer work = delegate(IDataReader reader) { workCalled++;
                                                                   reader.Read(); };
        Expect.Once.On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
        Expect.Once.On(con).Method("Open");
        Expect.Once.On(cmd).Method("ExecuteReader").WithNoArguments().Will(Return.Value(rdr));
        Expect.Once.On(rdr).Method("Close");
        Expect.Once.On(cmd).SetProperty("Connection");
        Expect.Once.On(con).Method("Dispose");
        Expect.Once.On(rdr).Method("Read").Will(Return.Value(true));

        using (CreatorScope scope = new CreatorScope(delegate { return con;}))
        {
            db.ExecuteSingleCommand(cmd, work, myConnectionStrings, IsolationLevel.ReadCommitted, null);
        }
        Assert.IsTrue(workCalled==1);
        mocks.VerifyAllExpectationsHaveBeenMet();
    }

    [Test]
    public void ExecutingABatchShouldInvokeWork2Times()
    {
        Mockery mocks = new Mockery();
        IDbCommand cmd = mocks.NewMock();
        IDbConnection con = mocks.NewMock();
        IDataReader rdr = mocks.NewMock();

        Database db = new Database();
        int workCalled = 0;
        DataReaderConsumer work = delegate(IDataReader reader)
        {
            workCalled++;
            reader.Read();
        };

        using (mocks.Ordered)
        {
            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            //Open connection once.
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //ExecuteReader for every "singlecommand" in the batch
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(Return.Value(rdr));
            Expect.Exactly(1).On(rdr).Method("Read").Will(Return.Value(true));
            //Close reader when done
            Expect.Exactly(1).On(rdr).Method("Close");
            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Open));
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //ExecuteReader for every "singlecommand" in the batch
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(Return.Value(rdr));
            Expect.Exactly(1).On(rdr).Method("Read").Will(Return.Value(true));
            //Close reader when done
            Expect.Exactly(1).On(rdr).Method("Close");
            Expect.Once.On(con).Method("Dispose");
        }
        using (CreatorScope scope = new CreatorScope(delegate { return con; }))
        {
            db.Execute(IsolationLevel.ReadCommitted, null, myConnectionStrings,
                       delegate
                           {
                               db.ExecuteSingleCommand(cmd, work, myConnectionStrings, IsolationLevel.ReadCommitted, null);
                               db.ExecuteSingleCommand(cmd, work, myConnectionStrings, IsolationLevel.ReadCommitted, null);
                           });
        }
        Assert.IsTrue(workCalled == 2);
        mocks.VerifyAllExpectationsHaveBeenMet();

    }

    [Test]
    [ExpectedException(typeof(OurException))]
    public void AttemptingABatchWithIsolationOfNoneShouldThrowOurException()
    {

        Database db = new Database();
        db.Execute(IsolationLevel.None, null, myConnectionStrings, null);
    }

    [Test]
    [ExpectedException(typeof (OurException))]
    public void AttemptingABatchWithNullWorkParameterShouldThrowOurException()
    {
        Database db = new Database();

        db.Execute(IsolationLevel.ReadCommitted, null, myConnectionStrings, null);
    }

    [Test]
    public void IfStatementRequiresNewTransactionDuringABatchWeShouldThrowOurException()
    {
        Mockery mocks = new Mockery();
        IDbCommand cmd = mocks.NewMock();
        IDbConnection con = mocks.NewMock();
        IDataReader rdr = mocks.NewMock();

        Database db = new Database();
        int workCalled = 0;
        DataReaderConsumer work = delegate(IDataReader reader)
        {
            workCalled++;
            reader.Read();
        };

        using (mocks.Ordered)
        {
            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            //Open connection once.
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //ExecuteReader for every "singlecommand" in the batch
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(Return.Value(rdr));
            Expect.Exactly(1).On(rdr).Method("Read").Will(Return.Value(true));
            //Close reader when done
            Expect.Exactly(1).On(rdr).Method("Close");
            //clean up connection on the way out.
            Expect.Once.On(con).Method("Dispose");
        }
        bool caughtException = false;
        try
        {
            using (CreatorScope scope = new CreatorScope(delegate { return con; }))
            {
                db.Execute(IsolationLevel.ReadCommitted, null, myConnectionStrings,
                           delegate
                               {
                                   db.ExecuteSingleCommand(cmd, work, myConnectionStrings, IsolationLevel.ReadCommitted, null);
                                   db.ExecuteSingleCommand(cmd, work, myConnectionStrings, IsolationLevel.ReadCommitted, null);
                               });
            }
        }
        catch (OurException e)
        {
            caughtException = true;
        }
        Assert.IsTrue(caughtException);
        mocks.VerifyAllExpectationsHaveBeenMet();
    }

    [Test]
    public void IfStatementHasIncompatibleIsolationTypeDuringABatchWeShouldThrowOurException()
    {
        Mockery mocks = new Mockery();
        IDbCommand cmd = mocks.NewMock();
        IDbConnection con = mocks.NewMock();
        IDataReader rdr = mocks.NewMock();

        Database db = new Database();
        int workCalled = 0;
        DataReaderConsumer work = delegate(IDataReader reader)
        {
            workCalled++;
            reader.Read();
        };

        using (mocks.Ordered)
        {
            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            //Open connection once.
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //ExecuteReader for every "singlecommand" in the batch
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(Return.Value(rdr));
            Expect.Exactly(1).On(rdr).Method("Read").Will(Return.Value(true));
            //Close reader when done
            Expect.Exactly(1).On(rdr).Method("Close");
            //clean up connection on the way out.
            Expect.Once.On(con).Method("Dispose");
        }
        bool caughtException = false;
        try
        {
            using (CreatorScope scope = new CreatorScope(delegate { return con; }))
            {
                db.Execute(IsolationLevel.ReadCommitted, null, myConnectionStrings,
                           delegate
                           {
                               db.ExecuteSingleCommand(cmd, work, myConnectionStrings,IsolationLevel.ReadCommitted, null);
                               db.ExecuteSingleCommand(cmd, work, myConnectionStrings,IsolationLevel.Snapshot, null);
                           });
            }
        }
        catch (OurException e)
        {
            caughtException = true;
        }
        Assert.IsTrue(caughtException);
        mocks.VerifyAllExpectationsHaveBeenMet();
    }

    [Test]
    public void ExecuteSingleCommandWithSnapshotIsolationShouldExecuteUnderSnapshotIsolation()
    {
        Mockery mocks = new Mockery();
        IDbCommand cmd = mocks.NewMock();
        IDbConnection con = mocks.NewMock();
        IDataReader rdr = mocks.NewMock();

        Database db = new Database();
        int workCalled = 0;
        DataReaderConsumer work = delegate(IDataReader reader)
        {
            workCalled++;
            reader.Read();
        };

        Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
        Expect.Once.On(con).Method("Open");
        Expect.Once.On(cmd).Method("ExecuteReader").WithNoArguments().Will(Return.Value(rdr));
        Expect.Once.On(rdr).Method("Close");
        Expect.Once.On(cmd).SetProperty("Connection");
        Expect.Once.On(con).Method("Dispose");
        Expect.Once.On(rdr).Method("Read").Will(Return.Value(true));

        using (CreatorScope scope = new CreatorScope(delegate { return con; }))
        {
            db.ExecuteSingleCommand(cmd, work, myConnectionStrings, IsolationLevel.Snapshot, new TimeSpan(20000));
        }
        Assert.IsTrue(workCalled == 1);
        mocks.VerifyAllExpectationsHaveBeenMet();
    }

    [Test]
    public void StatementFailsIfMirroringServerFailsOverwithSQLAndTransactionException()
    {
        Mockery mocks = new Mockery();
        IDbCommand cmd = mocks.NewMock();
        IDbConnection con = mocks.NewMock();
        IDataReader rdr = mocks.NewMock();

        Database db = new Database(2, 50);
        int workCalled = 0;
        DataReaderConsumer work = delegate(IDataReader reader)
        {
            workCalled++;
            reader.Read();
        };

        using (mocks.Ordered)
        {
            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            //Open connection once.
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //retry command for each retry.
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(
                Throw.Exception(SqlExceptionCreator.CreateSqlException("Blah", 8506,20)));

            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //retry command for each retry.
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(
                Throw.Exception(new TransactionInDoubtException("Transaction ambiguous")));

            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //retry command for each retry.
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(
                Throw.Exception(SqlExceptionCreator.CreateSqlException("Blah", 8506,20)));
            Expect.Once.On(con).Method("Dispose");
        }
        bool exceptionThrown = false;
        try
        {
            using (CreatorScope scope = new CreatorScope(delegate { return con; }))
            {
                db.ExecuteSingleCommand(cmd, work, myConnectionStrings, IsolationLevel.ReadCommitted, null);
            }
        }
        catch (OurException e)
        {
            Assert.AreEqual(8506, ((SqlException)e.InnerException).Number);
            exceptionThrown = true;
        }
        Assert.IsTrue(exceptionThrown);
        Assert.IsTrue(workCalled == 0);
        mocks.VerifyAllExpectationsHaveBeenMet();
    }

    [Test]
    public void StatementShouldThrowExceptionIfExecuteReaderThrowsExceptionWithErrorClassLessThan20()
    {
        Mockery mocks = new Mockery();
        IDbCommand cmd = mocks.NewMock();
        IDbConnection con = mocks.NewMock();
        IDataReader rdr = mocks.NewMock();

        Database db = new Database(2, 50);
        int workCalled = 0;
        DataReaderConsumer work = delegate(IDataReader reader)
        {
            workCalled++;
            reader.Read();
        };

        using (mocks.Ordered)
        {
            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            //Open connection once.
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //retry command for each retry.
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(
                Throw.Exception(SqlExceptionCreator.CreateSqlException("Blah", 22, 10)));
            Expect.Once.On(con).Method("Dispose");
        }
        bool exceptionThrown = false;
        try
        {
            using (CreatorScope scope = new CreatorScope(delegate { return con; }))
            {
                db.ExecuteSingleCommand(cmd, work, myConnectionStrings,IsolationLevel.ReadCommitted, null);
            }
        }
        catch (OurException e)
        {
            Assert.AreEqual(22, ((SqlException)e.InnerException).Number);
            exceptionThrown = true;
        }
        Assert.IsTrue(exceptionThrown);
        Assert.IsTrue(workCalled == 0);
        mocks.VerifyAllExpectationsHaveBeenMet();
    }

    [Test]
    public void SingleStatementShouldSucceedOnDualRailFailover()
    {
        Mockery mocks = new Mockery();
        IDbCommand cmd = mocks.NewMock();
        IDbConnection con = mocks.NewMock();
        IDataReader rdr = mocks.NewMock();

        Database db = new Database(2, 50);
        int workCalled = 0;
        DataReaderConsumer work = delegate(IDataReader reader)
        {
            workCalled++;
            reader.Read();
        };

        myConnectionStrings.Add("dualRail");

        using (mocks.Ordered)
        {
            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            //Open connection once.
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //retry command for each retry.
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(
                Throw.Exception(SqlExceptionCreator.CreateSqlException("Blah", 8506, 20)));

            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //retry command for each retry.
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(
                Throw.Exception(SqlExceptionCreator.CreateSqlException("Blah", 8506, 20)));

            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //retry command for each retry.
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(
                Throw.Exception(SqlExceptionCreator.CreateSqlException("Blah", 8506, 20)));
            Expect.Once.On(con).Method("Dispose");

            Expect.Exactly(1).On(con).GetProperty("State").Will(Return.Value(ConnectionState.Closed));
            //Open connection once.
            Expect.Once.On(con).Method("Open");
            Expect.Exactly(1).On(cmd).SetProperty("Connection");
            //retry command for each retry.
            Expect.Exactly(1).On(cmd).Method("ExecuteReader").WithNoArguments().Will(Return.Value(rdr));
            Expect.Once.On(rdr).Method("Read").Will(Return.Value(true));
            Expect.Once.On(rdr).Method("Close");
            Expect.Once.On(con).Method("Dispose");
        }
        bool exceptionThrown = false;
        try
        {
            using (CreatorScope scope = new CreatorScope(delegate { return con; }))
            {
                db.ExecuteSingleCommand(cmd, work, myConnectionStrings, IsolationLevel.ReadCommitted, null);
            }
        }
        catch (OurException e)
        {
            Assert.AreEqual(8506, ((SqlException)e.InnerException).Number);
            exceptionThrown = true;
        }
        Assert.IsFalse(exceptionThrown);
        Assert.IsTrue(workCalled == 1);
        mocks.VerifyAllExpectationsHaveBeenMet();
    }
}

Next Page »