Archive for CodeSmith tag
CodeSmith template to generate LINQ To SQL Data Context
If you are interested in what LINQ to SQL generates and don’t have Orcas installed or available right now but use CodeSmith try the following template to generate very similar code.
The primary difference is that this writes out the System types rather than the C# aliases (e.g. System.Int32 instead of int) but that could easily be changed but is binary compatible and otherwise almost identical to the source.
Download LINQ to SQL template (CodeSmith) (4 KB)
<%@ CodeTemplate Src="LinqFunctions.cs" Inherits="LinqFunctions" Language="C#" TargetLanguage="C#"
Description="Generates a data context and entities for given tables." %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Assembly Name="System.Data" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Data" %>
<%@ Property Name="DataContextClassName" Type="System.String" Category="Naming" Optional="True"Description="Name of the data context class to generate." %>
<%@ Property Name="Namespace" Type="System.String" Category="Naming" Optional="True" Description="Namespace for the data context class to generate." %>
<%@ Property Name="SourceTables" Type="SchemaExplorer.TableSchemaCollection" Category="Connection"Description="Tables to be mapped." %>
<%SchemaExplorer.DatabaseSchema database = SourceTables[0].Database;
string className = (String.IsNullOrEmpty(DataContextClassName)) ? DatabaseName(database) + "DataContext" : DataContextClassName;
Dictionary<TableSchema, List<TableKeySchema>> reverseForeignKeys = new Dictionary<TableSchema, List<TableKeySchema>>();
foreach(TableSchema table in SourceTables) {
foreach(TableKeySchema keySchema in table.ForeignKeys) {
if (reverseForeignKeys.ContainsKey(keySchema.PrimaryKeyTable)) {
reverseForeignKeys[keySchema.PrimaryKeyTable].Add(keySchema);
}
else {
List<TableKeySchema> keySchemas = new List<TableKeySchema>();
keySchemas.Add(keySchema);
reverseForeignKeys.Add(keySchema.PrimaryKeyTable, keySchemas);
}
}
}%>//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// CodeSmith template DeLINQuent.cst v0.1
// Generated by <%=CurrentUserName()%> at <%=DateTime.Now%>
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace <%=Namespace%>{
public partial class <%=className%> : global::System.Data.Linq.DataContext
{
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public <%=className%>(string connection) :
base(connection)
{
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public ProjectDataContext(global::System.Data.IDbConnection connection) :
base(connection) {
}
<% foreach(TableSchema table in SourceTables) {
string entityName = EntityName(table);
string propertyName = TableName(table);%>
public global::System.Data.Linq.Table<<%=entityName%>> <%=propertyName%> {
get {
return this.GetTable<<%=entityName%>>();
}
}
<% } %>
}<% foreach(TableSchema table in SourceTables) {
string entityName = EntityName(table);%>
[global::System.Data.Linq.Table(Name="<%=table.FullName%>")]
public partial class <%=entityName%> :global::System.Data.Linq.INotifyPropertyChanging,global::System.ComponentModel.INotifyPropertyChanged
{
<% foreach(ColumnSchema column in table.Columns) {%>
private <%=NullableSystemType(column)%> _<%=PropertyName(column)%>;
<% }
if (table.ForeignKeys.Count > 0) {%>
<% foreach(TableKeySchema keySchema in table.ForeignKeys) {
string foreignEntityName = EntityName(keySchema.PrimaryKeyTable);%>
private global::System.Data.Linq.EntitySet<<%=foreignEntityName%>> _<%=foreignEntityName%>;<%
}
}
if (reverseForeignKeys.ContainsKey(table)) {%>
<% foreach(TableKeySchema keySchema in reverseForeignKeys[table]) {
string propertyName = TableName(keySchema.ForeignKeyTable);%>
private global::System.Data.Linq.EntityRet<<%=EntityName(keySchema.ForeignKeyTable)%>> _<%=propertyName%>;
<% }
} %>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public <%=entityName%>() {
}
<% foreach(ColumnSchema column in table.Columns) {
string propertyName = PropertyName(column);%>
[global::System.Data.Linq.Column(Storage="_<%=propertyName%>", Name="<%=column.Name%>", DBType="<%=AttributeColumnDbType(column)%>"<%
if (column.IsPrimaryKeyMember) { %>, IsPrimaryKey=true<% }
if (!column.AllowDBNull) { %>, CanBeNull=false<% } %>)]
public <%=NullableSystemType(column)%> <%=propertyName%> {
get {
return this._<%=propertyName%>;
}
set {
if (this._<%=propertyName%> != value) {
this.OnPropertyChanging("<%=propertyName%>");
this._<%=propertyName%> = value;
this.OnPropertyChanged("<%=propertyName%>");
}
}
}
<% } %>
<% foreach(TableKeySchema keySchema in table.ForeignKeys) {
string propertyName = EntityName(keySchema.PrimaryKeyTable);
string tableName = TableName(keySchema.PrimaryKeyTable);%>
[global::System.Data.Linq.Association(Name="<%=keySchema.Name%>",
Storage="_<%=propertyName%>", OtherKey="<%=AttributeColumnList(keySchema.ForeignKeyMemberColumns)%>",
ThisKey="<%=AttributeColumnList(keySchema.PrimaryKeyMemberColumns)%>", IsForeignKey=true)]
public <%=propertyName%> <%=propertyName%> {
get {
return this._<%=propertyName%>.Entity;
}
set {
if (this._<%=propertyName%>.Entity != value) {
this.OnPropertyChanging("<%=propertyName%>");
if ((this._<%=propertyName%>.Entity != null)) {
<%=propertyName%> temp = this._<%=propertyName%>.Entity;
this._<%=propertyName%>.Entity = null;
temp.<%=TableName(table)%>.Remove(this);
}
this._<%=propertyName%>.Entity = value;
if ((value != null)) {
value.<%=TableName(table)%>.Add(this);
}
this.OnPropertyChanged("<%=propertyName%>");
}
}
}
<% } %>
<% if (reverseForeignKeys.ContainsKey(table)) {
foreach(TableKeySchema keySchema in reverseForeignKeys[table]) {
string propertyName = TableName(keySchema.ForeignKeyTable);%>
[global::System.Data.Linq.Association(Name="<%=keySchema.Name%>",
Storage="_<%=propertyName%>", OtherKey="<%=AttributeColumnList(keySchema.PrimaryKeyMemberColumns)%>",
ThisKey="<%=AttributeColumnList(keySchema.ForeignKeyMemberColumns)%>")]
public IEnumerable<<%=EntityName(keySchema.ForeignKeyTable)%>> <%=propertyName%> {
get {
return this._<%=propertyName%>;
}
}
<% }
} %>
public event global::System.ComponentModel.PropertyChangedEventHandler PropertyChanging;
public event global::System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
protected void OnPropertyChanging(string propertyName) {
if (this.PropertyChanging != null)
this.PropertyChanging(this, new global::System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
protected void OnPropertyChanged(string propertyName) {
if (this.PropertyChanged != null)
this.PropertyChanged(this, new global::System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
<% } %>
}
[)amien
My development tools
Christopher Bennage wrote about his development tool set-up and encouraged others to do the same so here’s my current set-up.
Daily tools
- Visual Studio 2005 – IDE of preference despite it’s sluggish behaviour
- SQL Server 2005 Management Studio – Took getting used to but it’s an improvement on 2000′s Enterprise Manager
- AnkhSVN - Subversion support inside Visual Studio 2005
- .NET Reflector – Searching .NET API or to find out what it’s doing
- Web Application Projects – Stop using VS’s web sites and start using web applications!
- Web Deployment Projects – Deploy to dev, test or live servers as easily as building a project
Not quite daily
- CodeSmith – Need to get to grips with v4 to build our whole database layer in one hit
- Trac – Bug tracking, milestones & wiki with integrated support for Subversion
- TortoiseSVN – Check-in/out of non-project items (e.g. art assets)
- Web Developer Extension – Trying CSS changes on-the-fly, validating pages etc. from Firefox
- Firebug – Examining pages, the page DOM etc. from Firefox
- KDiff – Excellent 3-way diff tool that works great with AnkhSVN
- Subtext – Blogging system running here
On occasion
- Visual C# Express and XNA – Messing with 3D graphics, controllers and pixel shaders
- Ogre – Steve’s object-oriented 3D engine
- XCode and Cocoa – Still quite alien with it’s message-based calling mechanism but obviously powerful
Keeping an eye on
- Eclipse – IDE for developing Java (C++ and C# support in various stages too)
- Ruby on Rails – Interesting RAD approach to web development – Apple also supporting on Mac OS X 10.5
- Sandcastle – Microsoft’s documentation tool that already seems to have had an impact on NDoc
- SubSonic – Build-provider that generates an ORM on the fly and provides automatic developer-only db editing pages
Not used lately, still installed
- Delphi 5/6 – Borland’s great RAD tool for non-.NET development, later versions support .NET too
- JBuilder – Java development although I’d probably move to Eclipse
- Visual Studio 2003 – Still required for the odd .NET 1.1 application/testing
[)amien
Choose your ORM: Runtime, code generation or build provider?
Selecting the right object-relational mapper is a tricky decision with many factors to weigh up.
One of the basic decisions is whether to go with a dynamic runtime (“black-box”) or a code generator.
I’m not a fan of the runtime approach – the discovery at runtime negatively impacts performance as it often uses reflection (or failing that post-compilation byte code modification) whilst robbing you of compile-time checking, IntelliPrompt support against your database objects, deployment and potentially licensing issues. In effect, it’s not that much better than a typed dataset.
Code generation provides for a much finer granularity letting you tweak the templates for the performance and features you need whilst also providing full compile-time checking and IntelliPrompt support.
Tools such as CodeSmith (my personal favourite), MyGeneration (free) do a good job of letting you write these templates and create the necessary ORM code but require being re-run every time you change the schema. During the starting phases of a project this could be quite often and goes against the whole concept of RAD.
So step in SubSonic and it’s build provider approach.
The idea here is that you modify your .config file to include the SubSonic build provider and it’s connection string, drop a simple text file in that lists which tables to work with and you’re done.
SubSonic now goes off to your database via the connection and generates all the code for tables you need and it’s magically there to be used like any other classes. Check out the demo to see just how easy it is.
SubSonic supports a large number of databases, has support for Enterprise Library, is open source and also provides simple “scaffold” pages that let you throw a basic web add/edit/update/delete table maintenance page by just throwing a table name attribute onto an empty page’s form element.
The only downside at this point is that it uses the ActiveRecord pattern for the ORM. If I manage to get some time to spend with it and can knock up a Domain Object + Data Mapper version I’ll let you know.
[)amien
My .NET toolkit
Every developer has his own favourite set of development tools and libraries that he’s come to rely on. Here’s a round-up of some I use or am looking at.
Actively using
- CodeSmith – Now in version 3 with it’s own IDE this tool lets you write templates that are executed against database structures. The C# ASP.Net style syntax is easy to get to grips with, allowing you to easily generate stored procedures, database scripts, class templates, simple object-relational-mappings, collection classes and the works. Will be less useful when .Net 2.0 arrives with Generics support but until then snap it up. A free version is available.
- NullableTypes – A shortcoming in .Net 1.1 is the lack of null support for value types outside the SQL Server name space. Until this is addressed in .Net 2.0 then check out this open-source library that does a sterling job. (Disclosure, I’ve contributed to this project)
- Subversion – A great source control tool, the replacement for the ageing CVS product. Gaining some good support now you can run the server directly or inside Apache. Combine with TortoiseSVN for Explorer shell based integration or AnkhSVN for integration inside the Visual Studio IDE.
- NUnit – Unit testing is a great way to prevent regressions and NUnit is both simple to learn and fast to use.
- VisualStyles – I’ve mentioned this before but .Net’s support for XP themes is abysmal with drawing problems all over the place especially when it comes to tab controls. VisualStyles is a free component you just drop on your form that magically fixes everything.
On my radar
- Trac – Provides wiki, issue tracking and source browsing over the top of a Subversion repository. I installed on my server at the weekend and it looks quite promising although its convoluted installation procedure had far too many dependencies for my liking. Will be testing this on a project I’m working on to see how it goes.
- PageMethods – Previously called SharpURL’s but now free and without an expiration this provides a way of identifying methods into a web page and the parameters they require.
I’m also on the lookout for a replacement for my object-relational CodeSmith templates I knocked up a while back and have been refining since. While they are functional and incredibly fast I’m now wanting features they don’t provide such as database independence, lazy loading and locking patterns.
[)amien