Sunday, November 8, 2009

Linq to SQL Partial Classes

While experimenting with Linq to SQL, I realized right away that I needed to extend the functionality of the entity classes generated by the Linq to SQL designer.  I wanted to be able to sort the entity classes by having them implement IComparable.

The solution turned out to be simple:  extend each entity class by defining a partial class, and implement IComparable in the partial class definition.  For example, I had an entity class Newspaper, which I extended with a partial class:

public partial class Newspaper : IComparable<Newspaper>
{
#region IComparable<Newspaper> Members
public int CompareTo(Newspaper other)
{
if (other == null)
throw new ArgumentNullException("other");
return Newspaper_Name.CompareTo(other.Newspaper_Name);
}
#endregion
}



Linq to SQL First Cut

I experimented a little bit with Linq to SQL and learned some of the basic syntax.  Here is a screenshot of the DBML designer file:

Capture

Here are two LINQ queries I developed with their ANSI SQL equivalents:

SELECT Newspapers.*
FROM Newspapers
INNER JOIN Newspapers_Advertisements
ON Newspapers.Newspaper_Id = Newspapers_Advertisements.Newspaper_Id
WHERE Newspapers_Advertisements.Advertisement_Id = '@guid'

List<Newspaper> allPapers = new List<Newspaper>();
allPapers.AddRange(
    from paper in db.Newspapers
    join paper_ad in db.Newspapers_Advertisements
        on paper.Newspaper_Id equals paper_ad.Newspaper_Id
     where paper_ad.Advertisement_Id == adId
     select paper
);

SELECT DISTINCT Newspapers.*
FROM Newspapers
WHERE Newspapers.Newspaper_ID NOT IN
(SELECT Newspapers_Advertisements.Newspaper_Id
FROM Newspapers_Advertisements
WHERE Newspapers_Advertisements.Advertisements_Id = '@guid')

List<Newspaper> allPapers = new List<Newspaper>();
allPapers.AddRange(
    (from paper in db.Newspapers
     where !db.Newspapers_Advertisements.Any(
         na => (na.Newspaper_Id == paper.Newspaper_Id
         & na.Advertisement_Id == adId))
     select paper).Distinct()
);

Thursday, November 5, 2009

.NET Solution Configuration Notes

I’ve been working recently on setting up a Continuous Integration server with CruiseControl.NET as my CI server, SubVersion for version control, and NUnit for unit testing.  One of the lessons I learned in the process is the importance of proper solution configuration so that the automated build and testing process works.  Many thanks to Jeff McWherter for his outstanding assistance in this endeavor.

Herein I’ll describe the final Visual Studio Solution configuration I used.  I am sure that this configuration could still use some fine-tuning for optimal CC.NET integration, but this is a working setup.  I will discuss how I configured CruiseControl.NET in a separate posting.

My .NET solution is for a console application.  I divided my solution into one project for the console application itself and then 5 other class library projects (each with a corresponding unit testing project).  I created a shared Lib folder to contain any 3rd party assemblies, including a local copy of any assembly referenced from the GAC (which I obtained by creating the reference, setting the Copy Local property to true, building the project, then moving the DLL to my Lib folder and recreating the reference to point to the DLL).  I could have put a separate Lib folder in each project folder, but decided that was overkill since the individual class libraries will never be shared with other solutions.

SolutionFolder

Jeff recommended that I also cross-reference my projects using Browse references to the built DLL files, rather than by using Project references.  This can be accomplished by setting the Build Output path to be bin\ for Debug and Release build configurations.  I decided against this approach after experimentation.  I found that my projects built without error on my CI server when using Project references.  Also, I found that my solution did not always build properly if I used Browse references, and I lost the nice functionality of being able to Go To Definition for any class outside of the active project.

Setting up the project references properly proved to be the most critical step in having successful CI builds.  Here are a few more conventions that I implemented when configuring this solution:

  • Set up my SVN ignore property (see below) following the guidelines I found in the Introducing Source Control MSDN article in the section describing which files are included and excluded in Visual Studio source control.
  • Created a SharedAssembly folder at the root level of my solution to contain AssemblyInfo.cs information shared by all of the projects in my solution.  The SharedAssembly folder contains two files:  AssemblyVersionInfo.cs and SharedAssemblyInfo.cs.  I configured, linked, and referenced these files following the instructions from Jeremy Jameson.
  • Included my .sln file in version control.  I found arguments both ways on this subject but decided that it made sense to include the .sln file for this solution.  The .sln file is built on the continuous integration server.

One possible improvement to be made is to run unit tests using MSBuild as part of the .csproj setup for each unit test project.  Craig Berntson makes this recommendation in his Continuous Integration for .NET Development white paper.  Instead, I set the unit tests to run using the CruiseControl.NET config file.

Here is my SubVersion ignore property list:

*.log
*.scc
*.suo
*.vbproj.user
*.csproj.user
*.vbproj.webinfo
*.csproj.webinfo
Bin
bin
Obj
obj