Tuesday, January 29, 2008

Build Your SubSonic DAL with NAnt

SubSonic is a .NET ORM (object relational mapping) tool with plenty of extras. In the ORM market, it can be compared to other tool such as Linq and NHibernate. I chose SubSonic over NHibernate, because of the ease of configuration or Linq, because I am still programming for .NET 2.0. That being said, there are three different ways to generate your data access layer using SubSonic:

  1. Using the command line by calling "sonic.exe"
  2. Using the SubSonic Tools for Visual Studio
  3. Using a build provider. However, this method is only available to web projects.

I was using the second method by installing the tools for Visual Studio. However, that got to be a pain since every time I want to regenerate the data access layer I have to start Visual Studio, wait for it to load, invoke the SubSonic tools, wait for the generation and finally rebuild the project.

So a few days ago I switched to using the first method - the command line. Once I did that, it was a matter of time before I wrote the NAnt build file to do it for me without Visual Studio - generate the data access layer and rebuild the data access layer dll. So here is the build file that can be used stand alone or even invoked through a pre-build event in Visual Studio:

<project name="Ensemble" default="build" basedir=".">
  <!-- The full path to the SubSonic directory where SubSonic.dll is found -->
  <property name="subSonicFullPath" value="c:\Program Files\SubSonic\SubSonic 2.0.3" />

  <!-- The full path to the SubSonic commander -->
  <property name="sonicCommanderFullPath" value="C:\Program Files\SubSonic\SubSonic 2.0.3\SubCommander\sonic.exe" />

  <!-- The command line arguments for the SubSonic commander -->
  <property name="sonicCommanderArguments" value="generate /lang vb" />

  <!-- The root namespace for the project -->
  <property name="build.rootNamespace" value="ensembleVideo" />

  <!-- The build type (release or debug) for the project -->
  <property name="build.config" value="release" />

  <!-- The relative path to the project directory (from the location of the build file) -->
	<property name="targetDirectoryRelativePath" value="../dataAccessLayer" overwrite="false" />

	<!-- The relative path to directory where SubSonic will generated the files (from the project target directory) -->
	<property name="subsonicGeneratedFilesRelativePath" value="generated" />

  <property name="targetDirectoryFullPath" value="${path::get-full-path(targetDirectoryRelativePath)}" overwrite="false" />
  <property name="subsonicGeneratedFilesFullPath" value="${path::combine(targetDirectoryFullPath, 'generated')}" />
	<property name="binDirectory" value="${path::combine(targetDirectoryFullPath, 'bin')}" overwrite="false" />

  <property name="buildDirectoryFullPath" value="${path::combine(binDirectory, build.config)}" overwrite="false" />
  <property name="buildOutput" value="ensembleVideo.dataAccessLayer.dll" />

  <!-- Default build target -->
	<target name="build">
	  <!-- Execute the SubSonic commander to generated the files in the defined "sonicCommanderFullPath" directory -->
    	commandline="${sonicCommanderArguments} /out "${subsonicGeneratedFilesFullPath}""
    	failonerror="true" />

    <!-- Execute the vb compiler to compile the SubSonic generated files -->
    <vbc target="library" output="${path::combine(buildDirectoryFullPath, buildOutput)}" rootnamespace="${build.rootNamespace}">
            <import namespace="System" />
            <import namespace="System.Data" />

          <!-- Include all the SubSonic generated files -->
          <include name="${subsonicGeneratedFilesFullPath}\*.vb" />

        <!-- Include a reference to the SubSonic dll -->
        <references basedir="${subSonicFullPath}">
  			  <include name="SubSonic.dll" />
// //]]>