D'Arcy from Winnipeg blogged about how he could not get a separate assembly for his DAL, and how this fact was making him give up on SubSonic.  This pretty much confused me, as I've done this exact feat for about 3 projects so far, so I'm assuming that he just doesn't know how to do it.  Sounds like a blog post to me.  In this blog I'll go over how I've setup a recent project.

I don't want to go into too much with the architecture decisions behind it, mainly because I change mine up about every 6 months or so in order to do things better, and so when I look at this post in a year I don't want to think about how stupid I was "then".  Anyway, lets continue.

Typically you want to have separation of certain concerns so that your code is cohesive and loosely coupled.  Go read some architecture books about those two words, essentially it means that we don't want to have to rewrite anything twice, and we want our code maintainable and easy to build upon in the future when the scope of our project expands.

For the majority of projects you're going to have a 3 layer setup.  Presentation, Business, and Data layers.  For the first, I create a project named "<ProjectName>.Web".  This contains all of my aspx pages.  These are the pages that are displayed to the user.  For my Business and Data layers with SubSonic I am able to squish them together into one project.  I call this "<ProjectName>.Data".

Now a red flag might go off at this moment, as I had just commented on how you want to separate the layers and then saw how I smush them together.  SubSonic uses partial classes which allow you generate your DAL, and then expand upon them with business objects.  Essentially you could have the generated DAL in it's own project with seperate namespace, but I find it much easier and faster to code to have them in the same project.  See if you agree with me after I give some examples.

Here's a shot of the Web and Data projects below.

Initial Project Setup 

To the meat of the post: Now within my Data project I need three key config files.  App, SubSonic, and Db.  SubSonic and Db will need to have the attribute "Copy to Output Directory" set to "Copy Always" ("Copy if newer" should also work, I just like it to always copy because I'm paranoid).

image

My App.Config is this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="SubSonicService" type="SubSonic.SubSonicSection, SubSonic" allowDefinition="MachineToApplication" restartOnExternalChanges="true" requirePermission="false"/>
    </configSections>
    <SubSonicService configSource="SubSonic.config" />
    <connectionStrings configSource="Db.config" />
</configuration>

SubSonic.Config is:

<?xml version="1.0" encoding="utf-8" ?>
<SubSonicService defaultProvider="Data" templateDirectory="Templates">
    <providers>
        <add
                 name="Data"
                 type="SubSonic.SqlDataProvider, SubSonic"
                 connectionStringName="DataCnx"
                 generatedNamespace="GamePlan.Data"
                 fixPluralClassName="true"
                 stripTableText="gp_"
                 stripViewText="_gp_"
                 includeTableList="gp_*"
                 includeProcedureList="gp_*"
                 excludeProcedureList="*security*"
        />
    </providers>
</SubSonicService>

the different attribute here are specific to your particular project.  Essentially I want to only generate objects for data objects in my database that have the gp prefix.

and Db.Config:

<?xml version="1.0" encoding="utf-8" ?>
<connectionStrings>
    <add name="DataCnx" providerName="System.Data.SqlClient" connectionString="Server=.\SQLEXPRESS;Database=GamePlan;Integrated Security=True;"/>
</connectionStrings>

I have also added a reference to the SubSonic.dll.  I place this dll in a "Dependency" folder at the root of my solution.  This way, I can upgrade external dependencies when I'm ready for them, not when a external project is updated.  It also makes it easy across multiple development machines

image

Within Visual Studio, in the "Tools" menu, I have a menu item named "SubSonic Generation" which I created by going to the "External Tools" and plopping this info:

image 

This stuff is covered in other tutorials, the main thing I want to point out is that I'm outputting generated classes to the "Generated" folder within my Data project.

I initially create my Generated folder, then run the "SubSonic Generation" menu item, then include those files within to the project.  DAL is now banged out.  At this point you could change things to output directly to the root folder of the Data project, and create a separate business project.  I choose not to do that as I have said before I massage them together using the partial modifier.

For example, if I need to modify the partial classes I create a new class in the root and go from there.  For example, if I wanted a FullName to be First + Last names I'd do something like:

public partial class User

{

FullName

{

return FirstName + " " + LastName;

}

}

Now, I can create what I'm gonna call factory business controllers.  Essentially I want no business logic within my presentation layer so I do something like:

namespace GamePlan.Data
{
    /// <summary>
    /// Controller class for gp_WorkGroupUser
    /// </summary>
    public partial class WorkGroupUserController
    {
        public static WorkGroupUserCollection GetUsersWorkGroups(object userId)
        {
            Guid Id = new Guid(userId.ToString());
            return new WorkGroupUserCollection()
            .Where(WorkGroupUser.Columns.UserId, Id)
            .Load();
        }
    }
}

This allows me in my presentation layer to write this:

private void BindWorkGroups()
        {
            MyWorkGroups.DataSource = Data.WorkGroupUserController.GetUsersWorkGroups(Membership.GetUser().ProviderUserKey);
            MyWorkGroups.DataBind();
        }

The last step to tying up the presentation layer to the data layer is to modify the web.config and add assemblies.

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="SubSonicService" type="SubSonic.SubSonicSection, SubSonic" allowDefinition="MachineToApplication" restartOnExternalChanges="true" requirePermission="false"/>

...

    </configSections>

<connectionStrings configSource="bin\Db.Config"/>
<SubSonicService configSource="bin\SubSonic.Config"/>

... rest of the config file...

When you build the solution the Config files from the Data project are copied over from it and placed in your bin directories.  This allows you to only have the one Db and SubSonic config files no matter how many projects you may need to use those values in.  If you are working with a WinForm, you may find those files in the bin\DEBUG or bin\RELEASE folders.

image

This one's gotten long enough, I'll have to go through and edit some more later.  You should get the gist :)

Sub Sonic - Look, its not me...its you!