Кодогенерация с CodeSmith

Posted: Сентябрь 25, 2010 in .NET, Кодогенерация

Раньше в начале 2000-х, когда еще не было Entity Framework, Hibernate только начал развиваться, а у меня появился мой первый мобильный телефон Siemens (модель не помню), работа с базой данных в среде ADO.NET выглядела примерно так

string connectionString =
	"Data Source=(local);Initial Catalog=Northwind;"
	+ "Integrated Security=true";

// Provide the query string with a parameter placeholder.
string queryString =
	"SELECT ProductID, UnitPrice, ProductName from dbo.products "
		+ "WHERE UnitPrice > @pricePoint "
		+ "ORDER BY UnitPrice DESC;";

// Specify the parameter value.
int paramValue = 5;

// Create and open the connection in a using block. This
// ensures that all resources will be closed and disposed
// when the code exits.
using (SqlConnection connection =
	new SqlConnection(connectionString))
{
	// Create the Command and Parameter objects.
	SqlCommand command = new SqlCommand(queryString, connection);
	command.Parameters.AddWithValue("@pricePoint", paramValue);

	// Open the connection in a try/catch block.
	// Create and execute the DataReader, writing the result
	// set to the console window.
	try
	{
		connection.Open();
		SqlDataReader reader = command.ExecuteReader();
		while (reader.Read())
		{
			Console.WriteLine("\t{0}\t{1}\t{2}",
				reader[0], reader[1], reader[2]);
		}
		reader.Close();
	}
	catch (Exception ex)
	{
		Console.WriteLine(ex.Message);
	}
	Console.ReadLine();

Тогда же появился замечательный инструмент для кодогенерации под название CodeSmith. Стоит он около 100 американских рублей, что делает его вполне доступным для легального использования. Этот замечательный инструмент позволяет создавать код на любом языке. Он предназначен не для создания законченных решений, а для облегчения написания каких-то рутинных действий, как, например, процедуры CRUD на TSQL и их обертки в ввиде Data Objects, Business Objects, Common Objects в среде C#.
Давайте рассмотрим его действие на примере создания объекта District. Это будет простой Common-объект состоящий только из свойств. Исходная таблица выглядит следующим образом

CREATE TABLE [dbo].[Districts](
	[District_ID] [int] NOT NULL PRIMARY KEY CLUSTERED,
	[District_Name] [nvarchar](100) NULL,
	[District_Name_Old] [nvarchar](100) NULL,
	[Date_Create] [smalldatetime] NOT NULL,
	[Date_Begin] [smalldatetime] NOT NULL,
	[Date_End] [smalldatetime] NULL
)

Запустим CodeSmith и создадим новый C# Template. Добавим свойства для имени исходной таблицы, автора, пространства имен, префикса таблицы, и нужно ли убирать окончание, если имя таблицы записано во множественном числе

<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context" Description="Table that the object is based on." %>
<%@ Property Name="Author" Type="System.String" Default="Maxim Masunov" Category="Style" Description="Author" %>
<%@ Property Name="BusinessLayerNameSpace" Type="System.String" Default="Common" Category="Style" Description="The Namespace of the Business Layer class" %>
<%@ Property Name="RemoveEndingS" Type="System.Boolean" Default="true" Category="Style" Description="If table name ends in s, class name will not if this is set to true." %>
<%@ Property Name="TablePrefix" Type="System.String" Default="t_" Category="Style" Description="Table Prefix" %>

Определим метод, который по имени таблицы будет создавать имя класса

<script runat="template">
public string GetClassName()
{
	if ((this.RemoveEndingS)
		&&(SourceTable.Name.EndsWith("s"))
		)
	{
		return RemovePrefix(SourceTable.Name.Substring(0,SourceTable.Name.Length -1));
	}
	else
	{
		return RemovePrefix(SourceTable.Name);
	}
}

public string RemovePrefix(string TableName)
{

	return TableName.Replace(TablePrefix,"");
}
</script>

И наконец нам нужно проитерировать все колонки, проставить их тип и добавить методы get, set. Окончательно файл шаблона будет выглядеть так

<%@ CodeTemplate Language="C#" TargetLanguage="C#" Src="" Inherits="CodeSmith.BaseTemplates.SqlCodeTemplate" Debug="False" Description="Template description here." %>
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context" Description="Table that the object is based on." %>
<%@ Property Name="Author" Type="System.String" Default="Maxim Masunov" Category="Style" Description="Author" %>
<%@ Property Name="BusinessLayerNameSpace" Type="System.String" Default="Common" Category="Style" Description="The Namespace of the Business Layer class" %>

<%@ Property Name="TablePrefix" Type="System.String" Default="t_" Category="Style" Description="Table Prefix" %>
<%@ Property Name="RemoveEndingS" Type="System.Boolean" Default="true" Category="Style" Description="If table name ends in s, class name will not if this is set to true." %>


<%@ Assembly Name="CodeSmith.BaseTemplates" %>
<%@ Assembly Name="System.Data" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="CodeSmith.BaseTemplates" %>


<% if (SourceTable.PrimaryKey == null) throw new ApplicationException("SourceTable does not contain a primary key."); %>
<% ColumnSchema primaryKey = SourceTable.PrimaryKey.MemberColumns[0]; %>

// Author:					<%= Author %>
// Created:					<%= DateTime.Now.Year.ToString() %>-<%= DateTime.Now.Month.ToString() %>-<%= DateTime.Now.Day.ToString() %>
// Last Modified:			<%= DateTime.Now.Year.ToString() %>-<%= DateTime.Now.Month.ToString() %>-<%= DateTime.Now.Day.ToString() %>
// 
// The use and distribution terms for this software are covered by the 
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)  
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by 
// the terms of this license.
//
// You must not remove this notice, or any other, from this software.
	
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;

namespace <%= BusinessLayerNameSpace %>
{
	
	public class <%= GetClassName() %> : BaseObject
	{

	<% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
		public <%= GetCSharpVariableType(SourceTable.Columns[i]) %> <%= SourceTable.Columns[i].Name %> 	{get;set;}
	<% } %>

	}
	
}

<script runat="template">
public string GetClassName()
{
	if ((this.RemoveEndingS)
		&&(SourceTable.Name.EndsWith("s"))
		)
	{
		return RemovePrefix(SourceTable.Name.Substring(0,SourceTable.Name.Length -1));
	}
	else
	{
		return RemovePrefix(SourceTable.Name);
	}
}

public string RemovePrefix(string TableName)
{
	return TableName.Replace(TablePrefix,"");
}
</script>

А вот код, который получился после запуска над таблицей Districts

// Author:					Maxim Masunov
// Created:					2010-9-25
// Last Modified:			2010-9-25
// 
// The use and distribution terms for this software are covered by the 
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)  
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by 
// the terms of this license.
//
// You must not remove this notice, or any other, from this software.
	
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;

namespace Common
{
	public class District : BaseObject
	{
		public int District_ID 	{get;set;}
		public string District_Name 	{get;set;}
		public string District_Name_Old 	{get;set;}
		public DateTime Date_Create 	{get;set;}
		public DateTime Date_Begin 	{get;set;}
		public DateTime Date_End 	{get;set;}
	}
}

Сейчас всю работу за нас выполняет Visual Studio при перетаскивании таблиц на поверхность Entity Model. Там же можно изменить названия полей на ваше усмотрения. Плюс все созданные классы помечаются как partial, что означает возможность их расширения не влезая в автоматически созданный код.

Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s