Mar 292013
 

Recently I was asked a question, as the title mentions of this post.

And I was just left with the ?? (Question) because I didn’t digged in so far previously in LINQ world before.

So let me start,

IEnumerable: This interface is designed to expose only the Enumerator, which would support a simple iteration over a non- generic collection.

This interface only enforces one method to be implemented by the class, with signature as

public IEnumerator GetEnumerator()

An example illustrating the sample implementation of IEnumerable

using System.Collections;
using System.Collections.Generic;

namespace LinqInterfacesExamples.Model
{
    public class ExampleIEnumerable : IEnumerable
    {
        private readonly string[] _internalList;
        private int _count;

        /// <summary>
        /// This is a constructor for the IEnumrable implementation class
        /// </summary>
        public ExampleIEnumerable()
        {
            _internalList = new string[100];
            _count = 0;
        }

        /// <summary>
        /// This is the method to populate the items into the internal array of the class
        /// </summary>
        /// <param name="value">This is a string value for to be added to the internal class list</param>
        public void Add(string value)
        {
            _internalList[_count] = value;
            _count++;
        }

        /// <summary>
        /// This is the interface method which need to be implemented for the IEnumerable interface
        /// </summary>
        /// <returns>IEnumerator</returns>
        public IEnumerator GetEnumerator()
        {
            for (int i = 0; i < _count; i++)
            {
                yield return _internalList[i];
            }
        }
    }
}

In the above example I have explicitly added the method to append items to the collection via “Add” method.

Note: The class is using a simple string array to store the items being added to the collection but still we are able to enumerate upon the same via the help of implementing the IEnumerable interface.

Comments: This is quick, good and simple methodology to expose non enumerable features of collections in an object with the help of “yield” keyword.

The implementation of the same would allow the use of “foreach” loop construct.

IEnumerator: This interface give the implementer a next level of granularity for the object to implement the following methods as follows:

Method

MoveNext

Reset

Property

Current

This interface most commonly is used to implement and return the object via custom class implementing the “IEnumerable” via the “GetEnumerator”.

The main purpose to use this interface to custom implement is for the following “Supports a simple iteration over a nongeneric collection.” As provided by MSDN link.

An example illustrating the sample implementation of IEnumerator

using System.Collections;

namespace LinqInterfacesExamples.Model
{
    public class ExampleIEnumerator : IEnumerator 
    {

        private object _current;
        private string[] _internalList;
        private int _count;
        private int _maxCount;

        public ExampleIEnumerator()
        {
            _internalList = new string[100];
        }

        public void Add(string value)
        {
            _internalList[_count] = value;
            if (_count > _maxCount)
                _maxCount = _count;
            _count++;
        }

        public bool MoveNext()
        {
            if(++_count < _maxCount)
            {
                _current = _internalList[_count];
                return true;
            }
            return false;
        }

        public void Reset()
        {
            _count = -1;
            _maxCount = -1;
        }

        public object Current
        {
            get { return _current; }
        }


    }
}

Comments: Thus using this interface allows the user of the implementation object to custom move the records by using the while loop and have the counter reset on the user command.

The implementation of the same would NOT allow the use of foreach loop construct.

IQueryable/ IQueryProvider

Pheww… Now the big ones…

IQueryable is more preferred to query data from out-memory (like remote database, service) collections.

Vs…

IEnumerable is more preferred for in-memory collection of data.

Simplifying above the IEnumerable collections first loads in all the data to the memory then applies the filter operation by the nature of the interface, where as the IQueryable interface is designed to modify the data retrieval query while being fired thus bringing in lesser amounts of data to the in-process memory and optimal for paging and incremental loading of data.

But interstingly IQueryable extends from IEnumerable*.

IQueryable works in conjunction with IQueryProvider whose interfaces are defined with the following methods:

IQueryable:

Properties

public Expression Expression {get;}
public Type ElementType {get;}
public IQueryProvider Provider {get;}

* IEnumerable (as IQueryable extends from the same):

Method

IEnumerator IEnumerable.GetEnumerator()

IQueryProvider:

Method

IQueryable<S> IQueryProvider.CreateQuery<S>(System.Linq.Expressions.Expression expression)

IQueryable IQueryProvider.CreateQuery(System.Linq.Expressions.Expression expression)

TResult IQueryProvider.Execute<TResult>(System.Linq.Expressions.Expression expression)

object IQueryProvider.Execute(System.Linq.Expressions.Expression expression)

The sample implementation of the same will be as follows:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace LinqInterfacesExamples.Model
{
    public class ExampleIQueryable: IQueryable<Employee> , IQueryProvider
    {
        private IList<Employee> _employee = new List<Employee>();
        private Expression _expression = null;
        
        #region Implementation of IEnumerable

        IEnumerator<Employee> IEnumerable<Employee>.GetEnumerator()
        {
            return (this as IQueryable).Provider.Execute<IEnumerator<Employee>>(_expression);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator<Employee>) (this as IQueryable).GetEnumerator();
        }

        #endregion

        #region Implementation of IQueryable

        public Expression Expression
        {
            get { return Expression.Constant(this); }
        }

        public Type ElementType
        {
            get { return typeof (Employee); }
        }

        public IQueryProvider Provider
        {
            get { return this; }
        }

        #endregion

        #region Custom Methods

        private void ProcessExpression(Expression expression)
        {
            if (expression.NodeType == ExpressionType.Equal)
            {
                ProcessEqualResult((BinaryExpression)expression);
            }
            if (expression.NodeType == ExpressionType.LessThan)
            {
                _employee = GetPersons();

                var query = from p in _employee
                            where p.Age < (int)GetValue((BinaryExpression)expression)
                            select p;
                _employee = query.ToList<Employee>();
            }
            if (expression is UnaryExpression)
            {
                UnaryExpression uExp = expression as UnaryExpression;
                ProcessExpression(uExp.Operand);
            }
            else if (expression is LambdaExpression)
            {
                ProcessExpression(((LambdaExpression)expression).Body);
            }
            else if (expression is ParameterExpression)
            {
                if (((ParameterExpression)expression).Type == typeof(Employee))
                {
                    _employee = GetPersons();
                }
            }
        }

        private void ProcessEqualResult(BinaryExpression expression)
        {
            if (expression.Right.NodeType == ExpressionType.Constant)
            {
                string name = (String)((ConstantExpression)expression.Right).Value;
                ProceesItem(name);
            }
        }

        private void ProceesItem(string name)
        {
            IList<Employee> filtered = new List<Employee>();

            foreach (Employee person in GetPersons())
            {
                if (string.Compare(person.FirstName, name, true) == 0)
                {
                    filtered.Add(person);
                }
            }
            _employee = filtered;
        }


        private object GetValue(BinaryExpression expression)
        {
            if (expression.Right.NodeType == ExpressionType.Constant)
            {
                return ((ConstantExpression)expression.Right).Value;
            }
            return null;
        }

        IList<Employee> GetPersons()
        {
            return new List<Employee>
            {
                new Employee { ID = 1, FirstName= "Mehfuz Hossain", Age=27},
                new Employee { ID = 2, FirstName= "Json Born", Age=30},
                new Employee { ID = 3, FirstName= "John Doe", Age=52}
            };

        }

        #endregion

        #region Implementation of IQueryProvider

        IQueryable<S> IQueryProvider.CreateQuery<S>(System.Linq.Expressions.Expression expression)
        {
            if (typeof(S) != typeof(Employee))
                throw new Exception("Only " + typeof(Employee).FullName + " objects are supported.");

            this._expression = expression;

            return (IQueryable<S>)this;
        }

        IQueryable IQueryProvider.CreateQuery(System.Linq.Expressions.Expression expression)
        {
            return (IQueryable<Employee>)(this as IQueryProvider).CreateQuery<Employee>(expression);
        }

        TResult IQueryProvider.Execute<TResult>(System.Linq.Expressions.Expression expression)
        {
            MethodCallExpression methodcall = _expression as MethodCallExpression;

            if (methodcall != null)
                foreach (var param in methodcall.Arguments)
                {
                    ProcessExpression(param);
                }
            return (TResult)_employee.GetEnumerator();
        }

        object IQueryProvider.Execute(System.Linq.Expressions.Expression expression)
        {
            return (this as IQueryProvider).Execute<IEnumerator<Employee>>(expression);
        }

        #endregion
    }
}

In the above example the same class which implements the IQueryable implements the IQueryProvider which is then also returned as Provider property.

The custom methods section (region) in the above code is designed for the expression tree parsing which I will explain in my subsequent blog post. But to keep it simple, this is the place where the LINQ logic gets executed upon the collection to filter out the results and return.

IQueryProvider, this section implements the methods CreateQuery/Execute where the method “Create” initializes the expression property of the IQueryProvider and upon which the “Execute” method is fired when the expression is actually evaluated (thus being lazy-loaded).

Comment: The implementation of the same would NOT allow the use of foreach loop construct.

The use of IQueryable is mostly used in the areas of querying external databases, web service collection or areas where query translation would help generate performance and additional benefits. (ex. ADO.NET Entity Framework)

The above code may look complex (for IQueryable interface) but digging in through the example via code stepping would help you understand the same.

Thank you, and please comment your views on the same and any corrections required for the same.

Downloads:
Download

Mar 272013
 

There are many numerous articles written upon the same but still I would like to re-iterate in this post the most common stated example to state the difference between the IQueryable and IEnumerable.

Difference:

IEnumerable: The collection implementing the IEnumerable interface is designed in a manner to do in-memory operations, where by the data is loaded altogether in one go to the memory and then filtered within the same.

When the following code is ran in conjunction with ADO.NET entity model the following resultant SQL query is fired to the server as below:

 using (AlphaDbEntities dc  = new AlphaDbEntities())
 {
       IEnumerable<Employee> enumrableList = from e in dc.Employees
                                             select e;

       List<Employee> empList1 = enumrableList.Take(10).ToList();
 }

Resulting TSQL:

SELECT 
[Extent1].[employeeId] AS [employeeId], 
[Extent1].[firstName] AS [firstName], 
[Extent1].[lastName] AS [lastName], 
[Extent1].[designation] AS [designation], 
[Extent1].[contactNumber] AS [contactNumber], 
[Extent1].[dateOfJoining] AS [dateOfJoining], 
[Extent1].[rating] AS [rating]
FROM [dbo].[Employees] AS [Extent1]


IQueryable: The collection implementing the IQueryable interface is designed in a manner to alter the LINQ query to a suitable/optimal query being fired on the external data source to filter out the data on the external data source itself and thus bringing in only the data required after filtration to the process in-memory.

This methodology is most suitable while working with large data sets and where paging mechanism also need to be implemented, and working with chunks of data would be sufficient for the application, rather than in memory analytics where entire data set is required within the memory for aggregations.

When the following code is ran in conjunction with ADO.NET entity model the following resultant SQL query is fired to the server as below:

 using (AlphaDbEntities dc  = new AlphaDbEntities())
 {
        IQueryable<Employee> queryableList = from e in dc.Employees
                                             select e;

        List<Employee> empList2 = queryableList.Take(10).ToList();
 }

Resulting TSQL:

SELECT TOP (10) 
1.[employeeId] AS [employeeId], 
1.[firstName] AS [firstName], 
1.[lastName] AS [lastName], 
1.[designation] AS [designation], 
1.[contactNumber] AS [contactNumber], 
1.[dateOfJoining] AS [dateOfJoining], 
1.[rating] AS [rating]
FROM [dbo].[Employees] AS 1

From the above I can conclude that IQueryable being smarter than IEnumerable is altering the query fired to the database and filtering the data on the database itself only (using the TOP 10 operator in TSQL), rather than compared to IEnumerable bringing in the entire set of data back to the application.

References:

http://msdn.microsoft.com/en-IN/library/system.collections.ienumerable.aspx
http://msdn.microsoft.com/en-IN/library/system.linq.iqueryable.aspx

Mar 272013
 

Previously I had been using the ReSharper and as most of the dev community is already praising the tool, let me add few more words of praises to the same via this article…

It’s a great tool because…

(Note: All the below shortcuts are under the ReSharper mapping of my VS2010, not its default)

1. Auto Generate Class/Folders (Alt+Insert)

reSharperImage1.bmp

2. Change to class names can be reflected over to files and more (Alt+Enter)

reSharperImage2.bmp

3. Removal of Unused reference (Alt+Enter)

reSharperImage3.bmp

4. Consistent variable naming conventions (Alt+Enter)

reSharperImage4.bmp

5. Auto-Generate Properties (Alt+Insert)

reSharperImage5.1.bmp

reSharperImage5.2.bmp

reSharperImage5.3.bmp

6. Auto Suggestions (Alt+Enter)

reSharperImage6.bmp

7. Code Refactor (Ctrl+Shift+R)

reSharperImage7.bmp

8. Navigate to the code members (Alt + \)

reSharperImage8.bmp

9. Move code block Up/Down (Ctrl+Alt+Shift+Up/Down Arrow)

reSharperImage9.bmp

10. File navigation (Ctrl + T)

reSharperImage10.bmp
And more and more as I explore…

One the best things I like about this tool is, that its design is well thought for the ease of use for the developers with quite simple shortcuts for the utility required to kick off.

But keeping my words less above I thought let the pictures describe its own beauty, but once again ReSharper is one of the best tools I have came across for the code development assistive tools.

Explore more by using it more, and I think it will defiantly impress you…

References:

http://www.jetbrains.com/resharper/

Mar 272013
 

Recently in a project I stumbled upon the same question as to how do I obtain the above information in an MS Graph format chart, whose data behind is kept in a datasheet (which not as pretty looking, as excel is these days…)

blog10_image1.bmp

And to add flavor to the same, I had to perform the same operation in C# code which is not so friendly with the syntax associated with the COM’s (for ex. Parametric Properties).

So, to cut the long story short the code below illustrates the methodology to read the above information off the MS Graph datasheet for your required purposes.

 private void btnTest_Click(object sender, RibbonControlEventArgs e)
        {
            PowerPoint.Application pptApp = Globals.ThisAddIn.Application;
            Graph.Chart msChart = pptApp.ActiveWindow.Selection.ShapeRange[1].OLEFormat.Object as Graph.Chart;
            Graph.DataSheet dataSheet = msChart.Application.DataSheet;

            //Datasheet
            //Get the column information (like Include)
            //The defination of Columns  is only aviable as "{Get}"
            //Check wether Column 2 is included in the MS Graph or not as Series. 
            Graph.Range columnRange = dataSheet.get_Range(dataSheet.Cells[1, 2], dataSheet.Cells[1, 2]).Columns;
            System.Diagnostics.Debug.WriteLine("Column 2 of the datasheet (Include): " + columnRange.Include);

            //Get the row information (like Include) 
            Graph.Range rowRange = dataSheet.get_Range(dataSheet.Cells[10, 1], dataSheet.Cells[10, 1]).Rows;
            System.Diagnostics.Debug.WriteLine("Row 10 of the datasheet (Include): " + columnRange.Include);

            //Get the number format of the cell
            Graph.Range cellRange = dataSheet.Cells[4, 2] as Graph.Range;
            System.Diagnostics.Debug.WriteLine("Cell 4(row),2(column) of the datasheet number format: " + cellRange.NumberFormat);

            //Get the value of the cell
            System.Diagnostics.Debug.WriteLine("Cell 4(row),2(column) of the datasheet value: " + cellRange.get_Value(Type.Missing));
        }

Downloads:
Download

Dec 222012
 

In few of my past projects I have always encountered the scenario multiple times; when for few glitches in the application I had to quite frequently change the SQL object attributes like table column names, stored procedure logic and more.

And for one or more changes to move into production involved generation of release script for the deployment each time which has been tedious so far and missing out on one or more set of changes has lead to multiple troubled releases.

Thus to address the above problem I have written a tool for myself to help me take care of deployment script generation (Create/Rollback) for the set of SQL objects, and associated preventive statements to make the production SQL scripts robust as possible. Also this tool generates a rollback script for the same set of objects, objects in-case the user/process calls for it.

Description:

This tool takes in your database details from which the SQL objects needs to be scripted, where the scripted files have to be stored and the list of SQL objects which need to be scripted in a text file.

1. Input file:
This file contains the list of SQL objects which needs to be scripted.

This file contain the set of markers which identify the SQL objects type and appropriate code type to be generated for them.

Example: sqlObjects.txt

<#TABLE#>dbo.TableAlpha
-Script the table with preventive code in place

<#TABLEWTIRGGERS#>dbo.TableBeta
-Script the table and its associated triggers with preventive code in place

<#STOREDPROCEDURE#>dbo.SP00Gamma
-Script the stored procedure with preventive code in place

<#USERDEFINEDFUNCTION#>dbo.FN00Theta
-Script user defined function with preventive code in place

<#TRIGGER#>dbo.TableBeta|TriggerName
-Script the trigger only associated with the specified table before marker with preventive code in place

2. Application configuration file:

Please specify the required details for the tool to generate scripts.

The tool uses the same scripting engine which SQL server management studio uses which produces the seamless result as required and easy enough to customise also. (Using the SQL Server Management Objects (SMO) libraries)

Tool Code:

class Program
    {
        static void Main(string[] args)
        {



            Server myServer = new Server(ConfigurationManager.AppSettings["sqlInstance"]);
            
            //Using windows authentication
            myServer.ConnectionContext.LoginSecure = true;
            myServer.ConnectionContext.Connect();

            if (myServer.ConnectionContext.IsOpen)
            {
                Database myDatabase = myServer.Databases[ConfigurationManager.AppSettings["sqlDatabase"]];

                string createPath = ConfigurationManager.AppSettings["createScriptPath"];
                string rollBackPath = ConfigurationManager.AppSettings["rollbackScriptPath"];

                if (File.Exists(createPath))
                {
                    File.Delete(createPath);
                }

                if (File.Exists(rollBackPath))
                {
                    File.Delete(rollBackPath);
                }

                Scripter scripter = new Scripter(myServer);
                ScriptingOptions createOptions  = new ScriptingOptions();
                createOptions.AnsiPadding = true;
                createOptions.ScriptBatchTerminator = true;
                createOptions.DriAll = true;
                createOptions.ToFileOnly = true;
                createOptions.FileName = createPath;
                createOptions.IncludeDatabaseContext = true;
                createOptions.IncludeIfNotExists = true;
                createOptions.AppendToFile = true;
                createOptions.AnsiFile = true;

                ScriptingOptions rollBackOptions = new ScriptingOptions();
                rollBackOptions.AnsiPadding = true;
                rollBackOptions.ScriptBatchTerminator = true;
                rollBackOptions.DriAll = true;
                rollBackOptions.ToFileOnly = true;
                rollBackOptions.FileName = rollBackPath;
                rollBackOptions.IncludeDatabaseContext = true;
                rollBackOptions.IncludeIfNotExists = true;
                rollBackOptions.AppendToFile = true;
                rollBackOptions.ScriptDrops = true;
                rollBackOptions.AnsiFile = true;

                StreamReader file = new StreamReader(ConfigurationManager.AppSettings["sqlObjects"]);

                string line;
                int counter = 0;

                while ((line = file.ReadLine()) != null)
                {
                    Console.WriteLine("Scripting : " + line);

                    //Insert Comments
                    string objectName;
                    if(line.Contains("<#TABLEWTIRGGERS#>"))
                    {
                        objectName = line.Replace("<#TABLEWTIRGGERS#>", "");

                        AppendTextToFile(createPath, "-- ***********************");
                        AppendTextToFile(createPath, "-- CREATE Script for : " + objectName);
                        AppendTextToFile(createPath, "-- ***********************");

                        AppendTextToFile(rollBackPath, "-- ***********************");
                        AppendTextToFile(rollBackPath, "-- DROP Script for : " + objectName);
                        AppendTextToFile(rollBackPath, "-- ***********************");

                        //Script tables
                        ScriptTables(myDatabase, createOptions, rollBackOptions, objectName.Split('.')[1], objectName.Split('.')[0]);
                        //Script Tiggers
                        ScriptTriggers(myDatabase, createOptions, rollBackOptions, objectName.Split('.')[1], null,
                                       objectName.Split('.')[0]);
                    }
                    else if (line.Contains("<#TABLE#>"))
                    {
                        objectName = line.Replace("<#TABLE#>", "");

                        AppendTextToFile(createPath, "-- ***********************");
                        AppendTextToFile(createPath, "-- CREATE Script for : " + objectName);
                        AppendTextToFile(createPath, "-- ***********************");

                        AppendTextToFile(rollBackPath, "-- ***********************");
                        AppendTextToFile(rollBackPath, "-- DROP Script for : " + objectName);
                        AppendTextToFile(rollBackPath, "-- ***********************");

                        //Script tables
                        ScriptTables(myDatabase, createOptions, rollBackOptions, objectName.Split('.')[1], objectName.Split('.')[0]);
                    }
                    else if (line.Contains("<#TRIGGER#>"))
                    {
                        objectName = line.Replace("<#TRIGGER#>", "");
                        string tableName = objectName.Split('|')[0];
                        string trigName = objectName.Split('|')[1];

                        AppendTextToFile(createPath, "-- ***********************");
                        AppendTextToFile(createPath, "-- CREATE Script for : " + objectName);
                        AppendTextToFile(createPath, "-- ***********************");

                        AppendTextToFile(rollBackPath, "-- ***********************");
                        AppendTextToFile(rollBackPath, "-- DROP Script for : " + objectName);
                        AppendTextToFile(rollBackPath, "-- ***********************");

                        //Script Tiggers
                        ScriptTriggers(myDatabase, createOptions, rollBackOptions, tableName.Split('.')[1], trigName,
                                       tableName.Split('.')[0]);
                    }
                    else if (line.Contains("<#STOREDPROCEDURE#>"))
                    {
                        objectName = line.Replace("<#STOREDPROCEDURE#>", "");

                        AppendTextToFile(createPath, "-- ***********************");
                        AppendTextToFile(createPath, "-- CREATE Script for : " + objectName);
                        AppendTextToFile(createPath, "-- ***********************");

                        AppendTextToFile(rollBackPath, "-- ***********************");
                        AppendTextToFile(rollBackPath, "-- DROP Script for : " + objectName);
                        AppendTextToFile(rollBackPath, "-- ***********************");

                        //Script Stored Procedures
                        ScriptStoredProcedure(myDatabase, createOptions, rollBackOptions, objectName.Split('.')[1], objectName.Split('.')[0]);
                    }
                    else if (line.Contains("<#USERDEFINEDFUNCTION#>"))
                    {
                        objectName = line.Replace("<#USERDEFINEDFUNCTION#>", "");

                        AppendTextToFile(createPath, "-- ***********************");
                        AppendTextToFile(createPath, "-- CREATE Script for : " + objectName);
                        AppendTextToFile(createPath, "-- ***********************");

                        AppendTextToFile(rollBackPath, "-- ***********************");
                        AppendTextToFile(rollBackPath, "-- DROP Script for : " + objectName);
                        AppendTextToFile(rollBackPath, "-- ***********************");

                        //Script User Defined Functions
                        ScriptUserDefinedFunctions(myDatabase, createOptions, rollBackOptions, objectName.Split('.')[1], objectName.Split('.')[0]);
                    }
                        counter++;
                }
                file.Close();
            }
        }

        private static void AppendTextToFile(string path, string text)
        {
            // This text is added only once to the file. 
            if (!File.Exists(path))
            {
                // Create a file to write to. 
                using (StreamWriter sw = File.CreateText(path))
                {
                    sw.WriteLine(text);
                }
            }
            else
            {
                using (StreamWriter sw = File.AppendText(path))
                {
                    sw.WriteLine(text);
                }
            }
        }

        private static void ScriptTables(Database sDatabase, ScriptingOptions cOption, ScriptingOptions rOption, string tableName, string schemaName)
        {
            Table table = sDatabase.Tables[tableName, schemaName];
            table.Script(cOption);
            table.Script(rOption);
        }

        private static void ScriptStoredProcedure(Database sDatabase, ScriptingOptions cOption, ScriptingOptions rOption, string procName, string schemaName)
        {
            StoredProcedure storedProcedure = sDatabase.StoredProcedures[procName, schemaName];
            storedProcedure.Script(cOption);
            storedProcedure.Script(rOption);
        }

        private static void ScriptUserDefinedFunctions(Database sDatabase, ScriptingOptions cOption, ScriptingOptions rOption, string funcName, string schemaName)
        {
            UserDefinedFunction userFunction = sDatabase.UserDefinedFunctions[funcName, schemaName];
            userFunction.Script(cOption);
            userFunction.Script(rOption);
        }

        private static void ScriptTriggers(Database sDatabase, ScriptingOptions cOption, ScriptingOptions rOption,string tableName , string trigName, string schemaName)
        {
            Table table = sDatabase.Tables[tableName, schemaName];
            foreach (Trigger trig in table.Triggers)
            {
                if (trigName == null)
                {
                    trig.Script(cOption);
                    trig.Script(rOption);
                }
                else if (trigName == trig.Name)
                {
                    trig.Script(cOption);
                    trig.Script(rOption);
                }
            }
        }
    }

Output:
createScript.sql

-- ***********************
-- CREATE Script for : dbo.TableBeta
-- ***********************
USE [alpha]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TableBeta]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[TableBeta](
	[activityLevelId] [numeric](15, 0) IDENTITY(1,1) NOT NULL,
	[activityLevelCode] [varchar](3) COLLATE Latin1_General_CS_AS NULL,
	[description] [varchar](16) COLLATE Latin1_General_CS_AS NOT NULL,
	[activityLevelValue] [int] NULL,
	[display] [tinyint] NULL,
	[sortOrder] [int] NULL,
	[lastUpdatedUser] [varchar](8) COLLATE Latin1_General_CS_AS NULL,
	[lastUpdatedDate] [datetime] NOT NULL,
 CONSTRAINT [ActivityLevel$activityLevelId] PRIMARY KEY CLUSTERED 
(
	[activityLevelId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = ON, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [alpha_Group1]
) ON [alpha_Group1]
END
GO
SET ANSI_PADDING ON
GO

rollbackScript.sql

-- ***********************
-- DROP Script for : dbo.TableBeta
-- ***********************
USE [alpha]
GO
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TableBeta]') AND type in (N'U'))
DROP TABLE [dbo].[TableBeta]
GO
-- ***********************
-- DROP Script for : dbo.SP00BetaProc
-- ***********************
USE [alpha]
GO
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SP00BetaProc]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[SP00BetaProc]
GO

Downloads:
Download

Refrences:
http://msdn.microsoft.com/en-us//library/ms162169.aspx