I want my foreign key to be mapped to a single object and not a collection

Say you have two tables:  Teams and Registrations

Registration has a foreign key for Teams :

image

In Subsonic 3, the Registration class will have a property called “Beach_Teams” which returns a IQueryable<Beach_Team> collection.

If we look at the generate class in the activerecord.cs file, there is a “Foreign Keys” region which contains the Beach_Teams property:


 #region ' Foreign Keys '
 public IQueryable<Beach_Team> Beach_Teams
 {
   get
   {
     var repo=LJR.DAL.Activities.Beach.Beach_Team.GetRepo();
     return from items in repo.GetAll()
          where items.TeamID == _TeamIDfk
          select items;
   }
 }

#endregion

It’s not ok for my use, I want a property returning only one “Beach_Team” object, so I can use it in my presentation layer with databound controls with no efforts

<asp:ListView runat="server" ID="LastTeams" DataSourceID="registrationsOds">
   <ItemTemplate>
     <%# Eval("Beach_Team.Name")%>
   </ItemTemplate>
 </asp:ListView>

So, what can I do ?

I can edit the ActiveRecord.cs file and add a property called “Beach_Team” and returning a Beach_Team object

 public Beach_Team Beach_Team
 {
   get
   {
     var repo = LJR.DAL.Activities.Beach.Beach_Team.GetRepo();
    return repo.GetByKey(_TeamIDfk);
   }
 }

It do the job !

But if I want to regenerate the ActiveRecord.cs file, my modification will be lost !

So the good solution is to modify the T4 template to generate this property.

Let’s do this :

Go to the ActiveRecord.tt file and search for ‘ Foreign Keys ‘.

Once you have find it look how it works:


#region ' Foreign Keys '
<#
 List<string> fkCreated = new List<string>();
 foreach(FKTable fk in tbl.FKTables)
 {
   if(IsTableOkToBeIncluded(fk.OtherTable))
   {
    string propName=fk.OtherQueryable;
    if(fkCreated.Contains(propName))
    {
      propName=fk.OtherQueryable+fkCreated.Count.ToString();
    }
    fkCreated.Add(fk.OtherQueryable);
#>
   public IQueryable<<#=fk.OtherClass #>> <#=propName #>
  {
  get
  {
     var repo=<#=Namespace #>.<#=fk.OtherClass#>.GetRepo();
     return from items in repo.GetAll()
         where items.<#=CleanUp(fk.OtherColumn)#> == _<#=CleanUp(fk.ThisColumn)#>
         select items;
   }
 }

<#
 }
 }
#>
 #endregion

In a nutshell, for each tables linked to the table we are on, we check if the access code to the table has to be generated (see my previous article : Subsonic : Specify the tables you really need ! ).

If the code has to be generated, we create a string variable named “propName” which will be the name of the property.

If this property already exists, we suffix the name to be sure we don’t have the same property twice.

Then we generate the IQueryable property.

Now, the first thing we want is to have the property name equals to the object name.

We could think that we don’t have to twist our minds because  we already have it with “fk.OtherClass” and i could be like that

 public <#=fk.OtherClass #> <#=fk.OtherClass #>
 {
  get
  {
   var repo=<#=Namespace #>.<#=fk.OtherClass#>.GetRepo();
   return repo.GetByKey(_<#=CleanUp(fk.ThisColumn)#>);
  }
 }

But what if we have two foreign keys to the same table ? We will have the same property twice! and we have to avoid it!

So, we have to check if this property isn’t already generated.

To do this, we can use the list “fkCreated” already present in the code, and create a “secondPropName” string variable, assign it the value of the OtherClass and check if it’s not already created :

 string secondPropName=fk.OtherClass;
 if(fkCreated.Contains(secondPropName))
 {
   secondPropName+=fkCreated.Count.ToString();
 }
 fkCreated.Add(secondPropName);

There is the final code


#region ' Foreign Keys '
<#
 List<string> fkCreated = new List<string>();
 foreach(FKTable fk in tbl.FKTables)
 {
   if(IsTableOkToBeIncluded(fk.OtherTable))
   {
    string propName=fk.OtherQueryable;
    if(fkCreated.Contains(propName))
    {
     propName=fk.OtherQueryable+fkCreated.Count.ToString();
    }
   fkCreated.Add(fk.OtherQueryable);

   string secondPropName=fk.OtherClass;
   if(fkCreated.Contains(secondPropName))
   {
     secondPropName+=fkCreated.Count.ToString();
   }
   fkCreated.Add(secondPropName);
#>
  public IQueryable<<#=fk.OtherClass #>> <#=propName #>
  {
    get
    {
      var repo=<#=Namespace #>.<#=fk.OtherClass#>.GetRepo();
      return from items in repo.GetAll()
        where items.<#=CleanUp(fk.OtherColumn)#> == _<#=CleanUp(fk.ThisColumn)#>
        select items;
    }
  }

  public <#=fk.OtherClass #> <#=secondPropName #>
  {
    get
    {
      var repo=<#=Namespace #>.<#=fk.OtherClass#>.GetRepo();
      return repo.GetByKey(_<#=CleanUp(fk.ThisColumn)#>);
    }
  }

<#
 }
 }
#>
 #endregion

Now I can use the linked object directly !

You can donwload my T4 templates here.

Subsonic : Specify the tables you really need !

With the Subsonic’s T4 Templates you can specify the tables you don’t want the access code to be generated.

But what if you want to choose the tables for which the mapping classes will be created ?

Actually you can have many reasons to do that : having an application using only specific tables from a big system or having the ability to separate distinct parts of a system by example.

In my case I wanted to use only three tables from my database to build an ASP.NET membership provider. This is the example I’ll use for this article.

So, in my database I have at least three tables :

  • Users
  • Roles
  • UsersInRoles

Now I want to generate the DAL layer only for these tables, so I create a new code library project, a add an app.config file containing the connection string and add the Subsonic.Core reference.

The I have to add my T4 template, but they are not ready. I have to modify them to allow the selection of my tables.

To do that, I go to the T4 template directory and edit the “Settings.ttinclude” and the “Context.tt” files :

T4TemplatesDirectory

First, check how it works

In the “Settings.ttinclude” file, line #30 we see the definition of the tables to be excluded:


//this is a list of tables you don't want generated
string[] ExcludeTables = new string[]{
"sysdiagrams",
"BuildVersion"
};

In the “Context.tt” file, il we search for “ExcludeTables”, we find three part of code using it in the same way:

// line 135

<#  foreach(Table tbl in tables){
if(!ExcludeTables.Contains(tbl.Name))
{

// ...

// line 251

foreach(Table tbl in tables)
{
if(!ExcludeTables.Contains(tbl.Name))
{

// ...

// line 271

foreach(Table tbl in tables)
{
if(!ExcludeTables.Contains(tbl.Name))
{

// ....

Now that we know how it’s working, we can modify the T4 templates to add the ability to choose the tables we want

The simplest option would be to replace the “ExcludeTables” array by “IncludeTables” and to remove the logical NOT operator (!) in the conditions and the job will be done.

But if we think a bit, we realize that there is many ways to choose the tables we want.
We can decide to choose :

  • All tables
  • All tables except the specified ones
  • Only the specified tables
  • All tables matching a pattern (example : starting by “MyApplication_”)
  • An other choice method

My solution :

In the “Settings.ttinclude” file:

Add a string array named “IncludeTables” containing the tables you want :


// this is the list of the tables you want to be generated
string[] IncludeTables = new string[]{
"Users",
"Roles",
"UsersInRoles"
};

Add a string variable named TablePrefix

 // the prefix of the table you want to be generated
 string TablePrefix="";

Add an enumeration named “TableChoiceMethod” and containing the different ways to choose the tables:


enum TableChoiceMethod
 {
SpecifiedExcludes,
SpecifiedIncludes,
SpecifiedPrefix,
All
 }

Add a variable for this enum, set to the value you want


// define the table choice method
 TableChoiceMethod tableChoiceMethod = TableChoiceMethod.SpecifiedIncludes;

Create  a ““IsTableOkToBeIncluded” method taking care of the choice we made in the activerecord file and returning whether or not the table is ok to be generated.


bool IsTableOkToBeIncluded(string tableName)
{
 switch(tableChoiceMethod)
 {
  case TableChoiceMethod.SpecifiedIncludes:
  {
   return IncludeTables.Contains(tableName);
  }
  case TableChoiceMethod.SpecifiedExcludes:
  {
   return !ExcludeTables.Contains(tableName);
  }
  case TableChoiceMethod.SpecifiedPrefix:
  {
  return tableName.StartsWith(TablePrefix, StringComparison.InvariantCultureIgnoreCase);
  }
  default: // assume TableChoiceMethod.All
  {
   return true;
  }
 }
}

In the Context.tt, ActiveRecord.tt and Struct.tt files :

Replace the condition”if(!ExcludeTables.Contains(tbl.Name))” by this method


<#  foreach(Table tbl in tables){
if(IsTableOkToBeIncluded(tbl.Name))
{

// ...

Now specify the Namespace, ConnectionStringName and DatabaseName in the Settings.ttinclude file.

Add the template to your DAL project,

Generate

You are done !

You can download my templates here.

Remarks :

  • The Subsonic version I use is 3.0.0.4.
  • I’m running Windows 7 64 bits and I had  unblock the files in windows explorer.
  • I had to run Visual Studio as an administrator.
  • If you are not familiar with subsonic, I invite you to watch the 5 minute demo and read the startup tutorial from the subsonicproject website.

Incoming search terms:

  • subsonic 3 0 tablename s

How to set two background images for an HTML page ?

The other day I was wondering how could I set two background images for an HTML page and I came with one solution.
I don’t know if it’s the best way to do that but it worked as I wanted.

To explain the solution, here is the complete steps I made

First I had an HTML page without any background:

Beach_withoutBackground

Then I added some CSS to set a background image :

bg

body
{
   background:url("img/bg.gif") no-repeat fixed left top #9AE4E8;
}

The result was good :
Beach_OneBackground
But I wanted to add a second background image on the right bottom :
logobeachrahier_medium
So I moved my background declaration for the head part of the html file

html
{
 background:url("img/bg.gif") no-repeat fixed left top #9AE4E8;
}

and I added an other background declaration for the body part

body
{
 background:url("img/logobeachrahier_medium.png") no-repeat fixed right bottom ;
}

The background declared for the body is applied over the html one:

Beach_TwoBackground
I think it’s Pretty good now.

Incoming search terms:

  • html background gifs
  • how to set img in html
  • background gif img
  • background html repeat
  • background page html
  • two background images cover html
  • background-bg
  • bg background gif
  • bg gif
  • how to add multiple background in htmlpage