Build 184.108.40.206 of T4 Toolbox includes a new, ready-to-use code generator that produces LINQ to SQL classes in C#. This generator uses .dbml file produced by the standard LINQ to SQL designer in Visual Studio and can be used as an alternative to the standard MSLinqToSqlGenerator.
You may be wondering why do we need yet another LINQ to SQL code generator, especially now that ADO.NET team placed it in maintenance mode in favor of the Entity Framework. Even though the Entity Framework may be more flexible and powerful, LINQ to SQL is currently the only data access framework built into .NET Framework and Visual Studio that allows modeling and generating both database and application code. LINQ to SQL strikes a good balance between simplicity and power, making it a great fit for a large class of business applications. Simplicity of modeling both database and application code makes it superior to Entity Framework on smaller projects that don’t require advanced O/R mapping or don’t need to access different types of data sources.
However, built-in code generation tools, SqlMetaL and MSLinqToSqlGenerator, have several limitations that make it difficult to scale LINQ to SQL solutions beyond the simplest scenarios. In particular, the application code is generated in a single file, which can reach size of tens of thousands lines of code for medium-sized databases and hundreds of thousands lines of code for large-size databases. The other limitation is the lack of direct generation of database source code. You can use CreateDatabase method of DataContext class to create a database based on a LINQ to SQL model. However, you will need to reverse engineer this database into another database tool, such as Visual Studio Database Edition or Enterprise Architect in order to model, maintain and evolve a database on a non-trivial project.
The code generator described in this article addresses the first limitation of LINQ to SQL by splitting generated DataContext and entity classes into separate .cs files. These files are a lot smaller and easier to work with than the monolithic designer.cs file produced by standard tools. The second limitation of not generating database code directly will be addressed by another code generator called "LINQ to SQL Schema", which is still under development. Together, these two code generators will enable true model-driven development approach for LINQ to SQL solutions.
- Download and install the latest version of T4 Toolbox from CodePlex.
- In Visual Studio, create a new or open an existing C# project and select Project->Add New Item in the main menu.
- In the Add New Item dialog, select Code Generation->LINQ to SQL model
- Enter the name you want to use for the new LINQ to SQL model (.dbml) file. Note that this name also determines name of the DataContext class that will be generated (NorthwindDataContext will be generated for Northwind.dbml). Click the Add button when finished.
Note that two files were added to your project - Northwind.dbml and Northwind.tt (depending on the name you entered in the Add New Item dialog).
This file contains a LINQ to SQL model. Based on its extension (.dbml) Visual Studio automatically opens the standard Object Relational Designer when you double-click this file in the Solution Explorer. You can populate the model using either the Toolbox or the Server Explorer.
- Populate the model by dragging all tables from the Northwind database in Server Explorer onto the design surface of Northwind.dbml.
- Save Northwind.dbml.
Note that standard Northwind.designer.cs file is not created under Northwind.dbml. This file is normally produced by the MSLinqToSqlGenerator, but in our case the standard code generator was replaced with Northwind.tt.
This is a T4 code generation file. It creates an instance of LinqToSqlGenerator class, assigns the DbmlFile property and calls the Run method to generate DataContext and entity classes for the specified .dbml file.
<# // <copyright file="Northwind.tt" company="Catapult Systems"> // Copyright © Catapult Systems. All Rights Reserved. // </copyright> #> <#@ template language="C#v3.5" hostspecific="True" #> <#@ output extension="log" #> <#@ include file="T4Toolbox.tt" #> <#@ include file="T4Toolbox\LinqToSql.tt" #> <# // Generate entity classes from a LINQ to SQL class model (.dbml file) LinqToSqlGenerator generator = new LinqToSqlGenerator(); generator.DbmlFile = "Northwind.dbml" generator.Run(); #>
Note that, unlike with MSLinqToSqlGenerator, DataContext and entity classes are not automatically regenerated when .dbml file changes. You will need to "Run Custom Tool" to regenerate the C# code manually.
- Right-click Northwind.tt in Solution Explorer and click Run Custom Tool item in the context menu.
Note that a number of .cs files were generated under Northwind.tt. Each of them contains a single class, which you can recognize by the first part of the file name: ClassName.generated.cs. All of these classes are declared as partial. You can extend these classes manually, by adding a new C# file to the project, such as Customer.cs to extend the partial class defined in Customer.generated.cs.
For complete details about this code generator, please refer to the following source files: LinqToSqlGenerator.tt, LinqToSqlDataContextTemplate.tt and LinqToSqlEntityClassTemplate.tt, which are installed in C:\Program Files\T4 Toolbox\T4Toolbox\LinqToSql directory by default.
Deviations from MSLinqToSqlGenerator
There are several important differences in code produced by this code generator compared to the standard MSLinqToSqlGenerator.
- While MSLinqToSqlGenerator uses fully-qualified, global:: type names, this template produces code with “using” directives and abbreviated names. This is done to make the generated code easier to read.
- While MSLinqToSqlGenerator generates field names as property name with an underscore prefix, this method simply converts the property name to camelCase. This is done for consistency with the StyleCop rule SA1306: Variable names must start with a lower-case letter.
- While MSLinqToSqlGenerator assumes that unknown data types are reference types this method assumes that unknown types are value types. Assuming that users will mostly use built-in types or known CLR types in the model, the most frequently used custom types will be enumerations. Treating unknown types as value types allows us to generate nullable enum types when model defines a nullable property.
- While MSLinqToSqlGenerator always emits InheritanceMapping attributes with inheritance code values enclosed in double quotation marks, making them strings, this generator emits them verbatim, preserving the original data type. This allows using enum values as inheritance code directly, without the need to convert. User can still use string values by enclosing them in double quotation marks in the model/designer.
- While MSLinqToSqlGenerator produces entity code that fires PropertyChanging event with empty property name, this template produces code fires PropertyChanging events with actual property names.
- While MSLinqToSqlGenerator produces a DataContext code that always uses an empty, explicitly created AttributeMappingSource in constructors that don’t receive mappingSource as a parameter, this generator simply calls the matching base constructor.
- Generation of method wrappers for stored procedures and functions is not supported at this time.
Give this code generator a try. I don’t claim to be a LINQ to SQL expert and will not be surprised if you find bugs or missing functionality. I would love to hear your feedback about this code generator and about the idea of model-first approach to LINQ to SQL solution development.
Special thanks to Jeff Odell, who did a lot of work on this code generator, and still refuses to blog.
- 3/9/2009. In version 220.127.116.11 of T4 Toolbox, name of the template changed from “LINQ to SQL classes” to “LINQ to SQL model”; name of the generator class changed from LinqToSqlClassesGenerator to LinqToSqlGenerator.
- 5/20/2009. Added a link to the article about schema generation capability added to the LINQ to SQL generator in version 9.5 of T4 Toolbox.