Mad Props!

Omniscience is just a Google-search away.

Login

You're reading Mabsterama, the weblog of Matt Hamilton. Enjoy your stay.

New Stuff in SQL Server 2008

Over on the Sql Stuff blog, Chad's posted a list of new features in next release of SQL Server (due in February). Reading through the list, a few stick out to me:

  • Compressed backup streams (say goodbye to those 12GB backup files)
  • date-only data type
  • HierarchyID data type (don't know much about this one, but it sounds fascinating)
  • Table-valued parameters (could this be the end of my split function?)
  • MERGE statement to insert or update a table depending on whether the row already exists(!)
  • Spatial data types for geography and geometry
  • No longer need IIS to run Reporting Services!
  • Export to Word from Reports

... and one feature called "subspace computation" which I accidentally read as "subspace communication" ... it's the new "Star Trek" feature of SQL Server! :)

SharePoint Workflows and "Pause Until"

I was just putting together a test workflow for a custom list in SharePoint which uses the "Pause Until" action, to pause the workflow until a certain date is reached and then send me an email. However, even if I set the date to today, the workflow never fired.

A quick Google-search later, I find this post on the SharePoint Designer Team Blog, outlining a hotfix for timed workflows in Windows Workflow Foundation. Downloaded it, installed it, now my workflows fire!

My only problem now is that a new workflow kicks off every time I change an item in my list (which is just fine), but the existing workflows from previous edits don't stop. That's no good to me if I change the date that I want the notification email sent. I'll get a bunch of emails on the old (wrong) dates.

Anyway: If you're working on workflows that need to wait for a duration or until a certain date, then you need this hotfix. Go get it!

Insert Amazon Link!

Here's a little test of a Windows Live Writer plugin from ScottIsAFool called "Insert Amazon Details". I'll post a list of items from my most recent order at amazon and see how they look on the site. Great idea, especially for my "Christmas Haul" posts (see 2005 parts one and two, 2006)!

Not a big fan of the description for each item (rather than just the name, it also includes the director and cast of a movie), but I don't think that's Scott's fault. All in all I'm pretty impressed with the ease with which it works!

 

 

 

 

 

 

And for Andrew (who will pay me back, right? Right???):

 

Amazon.com: Fray: Books: Joss Whedon

ISBN: 1569717516
ISBN-13: 9781569717516

Oz Legal System Inventates New Word

This one has been bugging me for a while now, but the topic came up again on the weekend and it has compelled me to post.

A year or so ago, Australia introduced a new series of "anti-terror" laws, one of which was the ability to hold a suspect for a defined length of time without charge - for questioning etc. There was a lot of controversy over the law, but it hadn't actually been tested until just recently when an Indian doctor in Queensland was held for questioning over the recent UK terror threat.

Here's my beef: The law is known as preventative detention.

What's wrong with that, you ask? Let's look at some other -ive words for a moment. If you're inventive, you're capable of invention. If something's restorative, it's capable of restoration. So if something is preventative ... is it capable of preventation? Of preventating something?

Unless I'm way off base, the word is preventive. I've heard media commentators use the correct term (preventive detention) a few times, but the official name is apparently the incorrect one.

This is similar to the whole "orientated" over "oriented" debacle (eg. describing software as "object orientated" when they mean "object oriented"). People seem to want to add that extra "ta" into the middle of words. It happens so much, it's almost like it's addictative!

Trainee Program part 5 - Connecting the Bits

Ok, we now have a Trainee object, an IDataProvider and TraineeDataContract class to formalize how we retrieve and save trainees, and an SqlDataProvider to actually talk to the database. We even have some tests to prove that they work (so far). All we need now is a way to change TraineeDataContract instances to Trainee instances, and back again.

This started pretty simple, but I expect we'll make it a bit more powerful later on. For now, we have a new constructor in our Trainee object which will let us create a Trainee from a TraineeDataContract:

 public Trainee(TraineeDataContract tdc) { ID = tdc.ID; FirstName = tdc.FirstName; LastName = tdc.LastName; IsActive = tdc.IsActive; }

... and a new method to convert back:

 public TraineeDataContract ToDataContract() { TraineeDataContract tdc = new TraineeDataContract(); tdc.ID = _id; tdc.FirstName = _firstName; tdc.LastName = _lastName; tdc.IsActive = _isActive; return tdc; }

I'm thinking that eventually we'll create a new TraineeCollection class (derived from ObservableCollection<Trainee>) in our object model, and give it a constructor that accepts an IList<TraineeDataContract>, so it can create a whole bunch of Trainee objects at once.

Looking good so far! Part 6 isn't written yet, because our next meeting hasn't happened. The next thing I'm thinking about is how to formalize the structure of a trainee, perhaps with an ITrainee interface which can be implemented by both Trainee and TraineeDataContract. Stay tuned!

Trainee Program part 4 - Unit Testing

Obviously in this little application we haven't taken the test-first approach. Maybe next time. For now, though, we needed a way to test our SqlDataProvider class, and NUnit seemed like a good solution.

We knocked up a new assembly which we called Qaf.TrainAlloc.Tests, and created a class therein called DataProviderTests. For starters, this class contained two tests: CanGetAllTrainees() and CanSaveTrainee(). Pretty straight forward. Here's one of 'em:

 [Test] public void CanGetAllTrainees() { IDataProvider dp = new SqlDataProvider(); IList<TraineeDataContract> list = dp.GetAllTrainees(); Assert.Greater(list.Count, 0, "GetAllTrainees return no trainees"); }

So we make ourselves a new SqlDataProvider and check that when we call GetAllTrainees() it returns more than one item.

Our first run of this test failed miserably, by the way. We had forgotten to open the SqlConnection before we called ExecuteReader on the command, so an exception was thrown. Hey - that's what unit tests are for, right? We successfully proved that our code was broken!

Once we fixed up that little bug, the test passed just fine!

Next step was to test that we can save a new or existing trainee back to the database. Here's our code for that:

 [Test] public void CanSaveTrainee() { TraineeDataContract tdc = new TraineeDataContract(); tdc.ID = Guid.NewGuid(); tdc.FirstName = "Fred"; tdc.LastName = "Bloggs"; tdc.IsActive = true; IDataProvider dp = new SqlDataProvider(); dp.SaveTrainee(tdc); SqlDataProvider sdp = new SqlDataProvider(); TraineeDataContract addedTdc = sdp.GetTrainee(tdc.ID); Assert.IsNotNull(addedTdc, "A trainee with the specified ID was not found!"); Assert.AreEqual(addedTdc.FirstName, tdc.FirstName, "The new trainee's first name is wrong"); Assert.AreEqual(addedTdc.LastName, tdc.LastName, "The new trainee's last name is wrong"); Assert.AreEqual(addedTdc.IsActive, tdc.IsActive, "The new trainee's active status is wrong"); tdc.FirstName = "Joe"; dp.SaveTrainee(tdc); sdp = new SqlDataProvider(); addedTdc = sdp.GetTrainee(tdc.ID); Assert.IsNotNull(addedTdc, "A trainee with the specified ID was not found!"); Assert.AreEqual(addedTdc.FirstName, tdc.FirstName, "The new trainee's first name is wrong"); }

Ok, so a quick look at that code should give you an idea of what we're doing. There's one new part in there, though - we call a method called SqlDataProvider.GetTrainee(Guid id). Where'd that come from?

Well, we cheated a bit. We needed a way to tell if our trainee had been saved correctly, so we added a GetTrainee method just to SqlDataProvider. It's not part of the IDataProvider interface, because we don't necessarily want it to be called in the final application. We could have added it to the test class, or made a helper class somewhere to do it, but what the hell.

So this class tests that we can save a new trainee, and, once saved, we can modify it. Great! One problem, though - every time we ran the test, it was creating a new trainee in our table. We didn't want that.

The solution was to add a "TestFixtureSetup" method and a "TestFixtureTearDown" method. You can think of these as constructors and destructors for tests - the setup method gets run at the start of the testing process, and the teardown method at the end.

Here they are in all their glory:

 private Guid _testID; [TestFixtureSetUp] public void SetUpTests() { _testID = Guid.NewGuid(); } [TestFixtureTearDown] public void TearDownTests() { SqlDataProvider sdp = new SqlDataProvider(); sdp.DeleteTrainee(_testID); } 

So we created a private Guid field called _testID, and also another helper method in SqlDataProvider called DeleteTrainee. We then used the _testID field in the CanSaveTrainee test rather than creating a new GUID each time. So now the trainee we created and modified gets deleted at the end of the testing process. Excellent!

What's next, then? Oh yeah - we still have no way to create our original Trainee objects from the TraineeDataContract objects that are coming back from the calls to IDataProvider. That's part 5!

Trainee Program part 3 - the SQL Provider

So we now have a Trainee class, and an IDataProvider interface. An interface is not much use without an implementation, so the next step is to create an SqlDataProvider class which impements IDataProvider.

I won't bore you with the details, but the SqlDataProvider class lives in its own assembly, but we kept it in the Qaf.TrainAlloc.DataProviders namespace. It uses SqlConnection, SqlCommand and SqlDataReader objects to talk to SQL Server. GetAllTrainees() builds up a List<TraineeDataContract> collection and returns it to the caller. SaveTrainee() checks if there is already a trainee with the supplied ID in the table, and creates or updates accordingly.

We now had the code written, and we knew it compiled, but we had no idea whether it was going to work. Ordinarily at this stage we'd have knocked up a console application to call the methods and check if they error, but we knew there was a better way than that. Enter NUnit - in the next post!

Trainee Program part 2 - the Data Provider

Now that we had a Trainee object, we needed a way to populate it from the database.

Since we knew that at some point we would want to make this an "n-tier" application, we decided to put a little bit of design-work in up-front, and instead of just connecting the object model directly to the database, we'd separate them out a bit.

So we started with a "data transfer object" class which mirrored the Trainee object, and would be the object that gets passed back and forth across our application layers. In keeping with some of the terminology introduced with .NET 3.0, we named it TraineeDataContract. I won't even paste the code in here because it's just a class with four public properties matching the properties of Trainee.

This class lives in an assembly called Qaf.TrainAlloc.DataProviders, along with an interface which defines all the ways we communicate with our data source:

 public interface IDataProvider  { IList<TraineeDataContract> GetAllTrainees(); void SaveTrainee(TraineeDataContract trainee); }

So a pretty simple interface for starters. We have a way to retrieve all the trainees, and a way to save a single trainee back to the database.

The end goal for this is to implement a couple of different ways of getting our data. The first will be a class to retrieve from, and save to, our SQL Server database. Later we can make another class which can retrieve from, and save to, a web service or WCF service that in turn uses the SQL Server class to talk to the database. In theory, this gives us the ability to swap out the data provider once the application is deployed. Choose it at runtime, even.

Next step is to implement the SQL Server data provider. See you in part 3!

Trainee Program part 1 - the Object Model

Here at work we have a fortnightly meeting of all six developers (when we can all make it) that we call the "developer jam session." It's two hours every two weeks where we can get together and talk about what we've been up to, and play around with various side projects.

At our last meeting we decided to kick off a new practice project. Rather than doing things the way we always do 'em - using typed DataSets and .NET 2.0 WinForms - we decided to catch up with the rest of the development world and try using an object model and WPF.

So I'm going to use this post (and perhaps a series of posts) to document what we're doing. I'm not saying that this is the right way to do it - far from it. In fact, this is more a request for comments from those of you who have developed real applications this way for years. Let me know what we're doing right and wrong, so we don't make too many false starts.

This particular application is starting small. Really small. It's a single SQL Server table of "trainees" who have an ID (uniqueidentifier), a first name and last name (varchar(50)) and a bit column representing whether they're "active". The program will need to be able to retrieve a list of all trainees and allow the user to add new ones and edit (including "deactivating") existing ones. Once we get it to that point, we're going to start adding new requirements and features.

The object model, then, as you'd imagine, is a single class called Trainee. It lives in its own little assembly and namespace (Qaf.TrainAlloc.ObjectModel), and looks like this:

 public class Trainee : INotifyPropertyChanged  { public Trainee() { ID = Guid.NewGuid(); IsActive = true; } private Guid _id; private string _firstName; private string _lastName; private bool _isActive; public Guid ID { get { return _id; } set  { _id = value; OnPropertyChanged("ID"); } } public string FirstName { get { return _firstName; } set  { _firstName = value; OnPropertyChanged("FirstName"); } } public string LastName { get { return _lastName; } set  { _lastName = value; OnPropertyChanged("LastName"); } } public bool IsActive { get { return _isActive; } set  { _isActive = value; OnPropertyChanged("IsActive"); } } protected void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }  #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged;  #endregion  } 

Pretty straight forward. We've implemented INotifyPropertyChanged up front because we know that we'll be binding to this class. We're doing it the .NET 2.0 way for now, because I think I was the only member of our group who had even heard of DependencyProperty, and it was a bit of a leap to use that straight away. We might change over to dependency properties at a later date.

The next step is to be able to retrieve a list of all trainees from the database, which will be the next post.

An EPG for Australia at Last?

I was just browsing the Australian Digital TV forums and found this post, which links to this press release from Free TV Australia.

'Twould seem that the local television networks have finally realised that there's an advantage to providing an electronic program guide to the public, and are getting together to publish a free solution.

For those lucky US readers who weren't aware: Up 'til now, the Australian free-to-air television networks have used copyright law (yes, copyright law) to protect their program guides - preventing anybody (including Microsoft) from providing a free EPG unless they manually enter the data. There are a few hacked-together solutions available for Windows Media Center (including the fantastic Free*EPG), but nothing official.

The only thing that concerns me is the paragraph in the press release that talks about the EPG data only being made available to vendors who comply with "some base level requirements designed to protect copyright, protect the integrity of the program information and facilitate collection of ratings information." That's a bit of a worry. I hope the ability to record a program doesn't mean we can't use the EPG!