├── LICENSE ├── License_DACFx.txt ├── License_SMO.txt ├── License_TSqlLangSvc.txt ├── README.md ├── dist ├── SqlSharpener.1.0.10.nupkg ├── SqlSharpener.nuspec └── tools │ ├── Microsoft.SqlServer.Dac.Extensions.dll │ ├── Microsoft.SqlServer.Dac.dll │ ├── Microsoft.SqlServer.TransactSql.ScriptDom.dll │ ├── SqlSharpener.XML │ └── SqlSharpener.dll ├── examples └── SimpleExample │ ├── .nuget │ └── packages.config │ ├── SimpleExample.DataLayer │ ├── App.config │ ├── EFCodeFirstExample.cs │ ├── EFCodeFirstExample.tt │ ├── ManualExample.tt │ ├── ManualExample.txt │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SimpleExample.DataLayer.csproj │ ├── StoredProcs.cs │ ├── StoredProcs.tt │ └── packages.config │ ├── SimpleExample.Database │ ├── Database.sqlproj │ └── dbo │ │ ├── Stored Procedures │ │ ├── usp_TaskCreate.sql │ │ ├── usp_TaskCreateMultiple.sql │ │ ├── usp_TaskGet.sql │ │ └── usp_TaskUpdate.sql │ │ ├── Tables │ │ ├── TaskStatus.sql │ │ └── Tasks.sql │ │ └── Types │ │ └── Tasks.sql │ ├── SimpleExamples.sln │ └── packages │ └── repositories.config └── src ├── .gitattributes ├── .gitignore ├── SqlSharpener.Tests ├── MetaBuilderTest.cs ├── Microsoft.SqlServer.Dac.xml ├── ProcedureHelperTest.cs ├── Properties │ └── AssemblyInfo.cs ├── SqlSharpener.Tests.csproj ├── app.config └── packages.config ├── SqlSharpener.sln └── SqlSharpener ├── AliasResolutionVisitor.cs ├── DataType.cs ├── DataTypeHelper.cs ├── ForeignKeyConstraintVisitor.cs ├── MetaBuilder.cs ├── Model ├── Column.cs ├── Parameter.cs ├── Procedure.cs ├── RelationshipIdentifier.cs ├── Select.cs ├── SelectColumn.cs ├── Table.cs └── View.cs ├── ProcedureHelper.cs ├── Properties └── AssemblyInfo.cs ├── SelectVisitor.cs ├── SqlSharpener.csproj ├── StoredProceduresTemplate.cs ├── StoredProceduresTemplate.tt ├── TextBuilder.cs ├── app.config └── packages.config /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Adam Eslinger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /License_DACFx.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeslinger0/sqlsharpener/197d116b577212af22ca450c4f4bc8795dcf3629/License_DACFx.txt -------------------------------------------------------------------------------- /License_SMO.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeslinger0/sqlsharpener/197d116b577212af22ca450c4f4bc8795dcf3629/License_SMO.txt -------------------------------------------------------------------------------- /License_TSqlLangSvc.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeslinger0/sqlsharpener/197d116b577212af22ca450c4f4bc8795dcf3629/License_TSqlLangSvc.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SqlSharpener 2 | Rather than generating code from the database or using a heavy abstraction layer that might miss differences between the database and data access layer until run-time, this project aims to provide a very fast and simple data access layer that is generated at **design-time** using SQL ___files___ as the source-of-truth (such as those found in an SSDT project) without having to deploy the database first. 3 | 4 | SqlSharpener accomplishes this by parsing the SQL files to create a meta-object hierarchy with which you can generate C# code such as stored procedure wrappers or Entity Framework Code-First entities. You can do this manually or by invoking one of the included pre-compiled T4 templates. 5 | 6 | # Donate 7 | 8 | If you find SqlSharpener to be useful, please consider making a [donation via PayPay](https://paypal.me/adam0101). Thank you. 9 | 10 | # Examples 11 | 12 | See examples of what SqlSharpener can do on the [Examples wiki page](https://github.com/aeslinger0/sqlsharpener/wiki/Examples). Also, a solution with the examples [is included with the code for you to download](https://github.com/aeslinger0/sqlsharpener/tree/master/examples/SimpleExample). 13 | 14 | # Performance 15 | 16 | According to the performance tests from [Dapper](https://github.com/StackExchange/dapper-dot-net#performance-of-select-mapping-over-500-iterations---poco-serialization), the best performance came from hand-coded functions using SqlDataReader. SqlSharpener gives you that performance without needing to hand-code your functions. 17 | 18 | # Installation 19 | 20 | [Using NuGet](https://www.nuget.org/packages/SqlSharpener/), run the following command to install SqlSharpener: 21 | 22 | PM> Install-Package SqlSharpener 23 | 24 | This will add SqlSharpener as a solution-level package. That means that the dll's do not get added to any of your projects (nor should they). 25 | 26 | # Quick Start 27 | 28 | See the [Quick Start Guide](https://github.com/aeslinger0/sqlsharpener/wiki/Quick-Start-Guide) for more examples. 29 | 30 | The fastest way to get up and running is to call one of SqlSharpener's included pre-compiled templates from your template. Add a new T4 template (\*.tt) file to your data project and set its content as follows: *(Ensure you have the correct version number in the dll path)* 31 | 32 | <#@ template debug="false" hostspecific="true" language="C#" #> 33 | <#@ assembly name="$(SolutionDir)\packages\SqlSharpener.1.0.2\tools\SqlSharpener.dll" #> 34 | <#@ output extension=".cs" #> 35 | <#@ import namespace="Microsoft.VisualStudio.TextTemplating" #> 36 | <#@ import namespace="System.Collections.Generic" #> 37 | <#@ import namespace="SqlSharpener" #> 38 | <# 39 | // Specify paths to your *.sql files. Remember to include your tables as well! We need them to get the data types. 40 | var sqlPaths = new List(); 41 | sqlPaths.Add(Host.ResolvePath(@"..\SimpleExample.Database\dbo\Tables")); 42 | sqlPaths.Add(Host.ResolvePath(@"..\SimpleExample.Database\dbo\Stored Procedures")); 43 | 44 | // Set parameters for the template. 45 | var session = new TextTemplatingSession(); 46 | session["outputNamespace"] = "SimpleExample.DataLayer"; 47 | session["procedurePrefix"] = "usp_"; 48 | session["sqlPaths"] = sqlPaths; 49 | 50 | // Generate the code. 51 | var t = new SqlSharpener.StoredProceduresTemplate(); 52 | t.Session = session; 53 | t.Initialize(); 54 | this.Write(t.TransformText()); 55 | #> 56 | 57 | The generated .cs file will contain a class with functions for all your stored procedures, DTO objects for procedures that return records, and an interface you can used if you use dependency-injection. Whenever your database project changes, simply right-click on the .tt file and click "Run Custom Tool" to regenerate the code. 58 | 59 | # Usage 60 | 61 | Once the code is generated, your business layer can call it like any other function. Here is one example: 62 | 63 | public TaskGetDto Get(int id) 64 | { 65 | return storedProcedures.TaskGet(id); 66 | } 67 | 68 | # Dependency Injection 69 | 70 | If you use a dependency-injection framework such as Ninject, you can use the interface generated. For example: 71 | 72 | public class DataModule : NinjectModule 73 | { 74 | public override void Load() 75 | { 76 | Bind().To(); 77 | } 78 | } 79 | 80 | # Documentation 81 | 82 | Check out the [wiki](https://github.com/aeslinger0/sqlsharpener/wiki) for more info. 83 | 84 | # License 85 | 86 | SqlSharpener uses The MIT License (MIT), but also has dependencies on DacFx and ScriptDom. I have included their license info in the root directory. 87 | -------------------------------------------------------------------------------- /dist/SqlSharpener.1.0.10.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeslinger0/sqlsharpener/197d116b577212af22ca450c4f4bc8795dcf3629/dist/SqlSharpener.1.0.10.nupkg -------------------------------------------------------------------------------- /dist/SqlSharpener.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SqlSharpener 5 | 1.0.10 6 | SqlSharpener 7 | Adam Eslinger 8 | Adam Eslinger 9 | https://github.com/aeslinger0/sqlsharpener/blob/master/LICENSE 10 | https://github.com/aeslinger0/sqlsharpener 11 | false 12 | Parses SQL files to create a meta-object hierarchy with which you can generate C# code such as stored procedure wrappers or Entity Framework entities. Includes templates. Go to https://github.com/aeslinger0/sqlsharpener for more info! 13 | 05/26/2015 14 | -- Added primary and foreign key relationships to the meta-model. 15 | 16 | 05/14/2015 : version 1.0.9 17 | -- Added support for UNION clauses. 18 | -- Added support for table-valued parameters. 19 | -- Added support for generic POCO objects. 20 | -- Fixed bugs with multi-set results. 21 | -- Added null-check for SqlReader when reading nullable columns. 22 | -- Made all methods virtual. 23 | 24 | 04/28/2015 : version 1.0.8 25 | -- Added function overloads that accept an object with a property for each parameter. 26 | -- Added views to the meta builder. 27 | -- Made primatives nullable only if database column is nullable. 28 | -- Made connection string a constructor parameter (so it can be injected with Ninject) instead of using ConfigurationManager. 29 | -- Changed return value to be an object with Data<T> and RecordsAffected as properties. 30 | 31 | 04/23/2015 : version 1.0.6 - 1.0.7 32 | -- Added tables to the meta builder. 33 | -- Refactored code to be more object-oriented. 34 | -- Added more XML comments to generated code. 35 | 36 | 04/21/2015 :version 1.0.0 - 1.0.5 37 | -- Fixed bugs with partial methods and DTO object. 38 | -- Added support for ExecuteScalar(). 39 | -- Added partial method hooks. 40 | -- Added support for returning an array of primitives. 41 | -- Added XML comments to generated functions. 42 | 43 | Copyright 2015 44 | dac ScriptDom SSDT C# CodeGen T4 45 | 46 | -------------------------------------------------------------------------------- /dist/tools/Microsoft.SqlServer.Dac.Extensions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeslinger0/sqlsharpener/197d116b577212af22ca450c4f4bc8795dcf3629/dist/tools/Microsoft.SqlServer.Dac.Extensions.dll -------------------------------------------------------------------------------- /dist/tools/Microsoft.SqlServer.Dac.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeslinger0/sqlsharpener/197d116b577212af22ca450c4f4bc8795dcf3629/dist/tools/Microsoft.SqlServer.Dac.dll -------------------------------------------------------------------------------- /dist/tools/Microsoft.SqlServer.TransactSql.ScriptDom.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeslinger0/sqlsharpener/197d116b577212af22ca450c4f4bc8795dcf3629/dist/tools/Microsoft.SqlServer.TransactSql.ScriptDom.dll -------------------------------------------------------------------------------- /dist/tools/SqlSharpener.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeslinger0/sqlsharpener/197d116b577212af22ca450c4f4bc8795dcf3629/dist/tools/SqlSharpener.dll -------------------------------------------------------------------------------- /examples/SimpleExample/.nuget/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/EFCodeFirstExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | using System.Data.Entity; 6 | 7 | namespace SimpleExample.EntityFrameworkCodeFirst 8 | { 9 | public partial class TaskContext : DbContext 10 | { 11 | public TaskContext(): base() 12 | { 13 | } 14 | public DbSet Tasks { get; set; } 15 | public DbSet TaskStatus { get; set; } 16 | } 17 | 18 | 19 | [Table("Tasks")] 20 | public partial class Tasks 21 | { 22 | 23 | [Key] 24 | [Required] 25 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 26 | public Int32? Id { get; set; } 27 | 28 | [Required] 29 | [MaxLength(50)] 30 | public String Name { get; set; } 31 | 32 | [Required] 33 | [MaxLength(1000)] 34 | public String Description { get; set; } 35 | 36 | [Required] 37 | public Int32? TaskStatusId { get; set; } 38 | [ForeignKey("Id")] 39 | public virtual TaskStatus TaskStatus { get; set; } 40 | 41 | [Required] 42 | public DateTime? Created { get; set; } 43 | 44 | [Required] 45 | [MaxLength(50)] 46 | public String CreatedBy { get; set; } 47 | 48 | [Required] 49 | public DateTime? Updated { get; set; } 50 | 51 | [Required] 52 | [MaxLength(50)] 53 | public String UpdatedBy { get; set; } 54 | } 55 | 56 | [Table("TaskStatus")] 57 | public partial class TaskStatus 58 | { 59 | 60 | [Key] 61 | [Required] 62 | public Int32? Id { get; set; } 63 | public virtual ICollection Tasks { get; set; } 64 | 65 | [Required] 66 | [MaxLength(50)] 67 | public String Name { get; set; } 68 | } 69 | } -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/EFCodeFirstExample.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="true" language="C#" #> 2 | <#@ assembly name="$(SolutionDir)\packages\SqlSharpener.1.0.10\tools\SqlSharpener.dll" #> 3 | <#@ assembly name="System.Core" #> 4 | <#@ import namespace="System.Linq" #> 5 | <#@ import namespace="System.Text" #> 6 | <#@ import namespace="System.Collections.Generic" #> 7 | <#@ import namespace="SqlSharpener" #> 8 | <#@ output extension=".cs" #> 9 | <# 10 | // Ensure the SqlSharpener version number above matches the version you installed! 11 | 12 | // Create a new MetaBuilder 13 | var meta = new MetaBuilder(); 14 | 15 | // Specify paths to your *.sql files. Remember to include your tables as well! We need them to get the data types. 16 | meta.SqlPaths.Add(Host.ResolvePath(@"..\SimpleExample.Database\dbo\Tables")); 17 | meta.SqlPaths.Add(Host.ResolvePath(@"..\SimpleExample.Database\dbo\Stored Procedures")); 18 | #> 19 | using System; 20 | using System.Collections.Generic; 21 | using System.ComponentModel.DataAnnotations; 22 | using System.ComponentModel.DataAnnotations.Schema; 23 | using System.Data.Entity; 24 | 25 | namespace SimpleExample.EntityFrameworkCodeFirst 26 | { 27 | public partial class TaskContext : DbContext 28 | { 29 | public TaskContext(): base() 30 | { 31 | } 32 | <# foreach(var tbl in meta.Tables){ #> 33 | public DbSet<<#=tbl.Name#>> <#=tbl.Name#> { get; set; } 34 | <# } #> 35 | } 36 | 37 | <# foreach(var tbl in meta.Tables){ #> 38 | 39 | [Table("<#=tbl.Name#>")] 40 | public partial class <#=tbl.Name#> 41 | { 42 | <# foreach(var col in tbl.Columns){ #> 43 | 44 | <# if(col.IsPrimaryKey) { WriteLine(" [Key]"); } #> 45 | <# if(!col.IsNullable) { WriteLine(" [Required]"); } #> 46 | <# if(col.Length > 0) { WriteLine(" [MaxLength({0})]", col.Length); } #> 47 | <# if(col.IsIdentity) { WriteLine(" [DatabaseGenerated(DatabaseGeneratedOption.Identity)]"); } #> 48 | public <#=col.DataTypes[TypeFormat.DotNetFrameworkType]#> <#=col.Name#> { get; set; } 49 | <# foreach( var parent in col.ParentRelationships){ #> 50 | [ForeignKey("<#=parent.Columns.First()#>")] 51 | public virtual <#=parent.TableOrView#> <#=parent.TableOrView#> { get; set; } 52 | <# } #> 53 | <# foreach( var child in col.ChildRelationships){ #> 54 | public virtual ICollection<<#=child.TableOrView#>> <#=child.TableOrView#> { get; set; } 55 | <# }} #> 56 | } 57 | <# } #> 58 | } -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/ManualExample.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="true" language="C#" #> 2 | <#@ assembly name="$(SolutionDir)\packages\SqlSharpener.1.0.10\tools\SqlSharpener.dll" #> 3 | <#@ assembly name="System.Core" #> 4 | <#@ import namespace="System.Linq" #> 5 | <#@ import namespace="System.Text" #> 6 | <#@ import namespace="System.Collections.Generic" #> 7 | <#@ import namespace="SqlSharpener" #> 8 | <#@ output extension=".txt" #> 9 | <# 10 | // Ensure the SqlSharpener version number above matches the version you installed! 11 | 12 | // Create a new MetaBuilder 13 | var meta = new MetaBuilder(); 14 | 15 | // Specify paths to your *.sql files. Remember to include your tables as well! We need them to get the data types. 16 | meta.SqlPaths.Add(Host.ResolvePath(@"..\SimpleExample.Database\dbo\Tables")); 17 | meta.SqlPaths.Add(Host.ResolvePath(@"..\SimpleExample.Database\dbo\Stored Procedures")); 18 | meta.ProcedurePrefix = "usp_"; 19 | #> 20 | 21 | TABLES: 22 | <# foreach(var tbl in meta.Tables){ #> 23 | <#=tbl.Name#> 24 | <# foreach(var col in tbl.Columns){ #> 25 | <#=col.Name#> (<#=col.DataTypes[TypeFormat.DotNetFrameworkType]#>) 26 | <# } #> 27 | 28 | <# } #> 29 | 30 | STORED PROCEDURES: 31 | <# foreach(var proc in meta.Procedures){ #> 32 | <#=proc.Name#> 33 | Parameters 34 | <# foreach(var p in proc.Parameters){ #> 35 | <#=p.Name#> (<#=p.DataTypes[TypeFormat.DotNetFrameworkType]#>) 36 | <# } #> 37 | 38 | <# } #> -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/ManualExample.txt: -------------------------------------------------------------------------------- 1 |  2 | TABLES: 3 | Tasks 4 | Id (Int32?) 5 | Name (String) 6 | Description (String) 7 | TaskStatusId (Int32?) 8 | Created (DateTime?) 9 | CreatedBy (String) 10 | Updated (DateTime?) 11 | UpdatedBy (String) 12 | 13 | TaskStatus 14 | Id (Int32?) 15 | Name (String) 16 | 17 | 18 | STORED PROCEDURES: 19 | TaskCreate 20 | Parameters 21 | Name (String) 22 | Description (String) 23 | TaskStatusId (Int32?) 24 | Created (DateTime?) 25 | CreatedBy (String) 26 | Updated (DateTime?) 27 | UpdatedBy (String) 28 | TaskId (Int32?) 29 | 30 | TaskCreateMultiple 31 | Parameters 32 | tasks (Object) 33 | 34 | TaskGet 35 | Parameters 36 | TaskId (Int32?) 37 | 38 | TaskUpdate 39 | Parameters 40 | TaskId (Int32?) 41 | Name (String) 42 | Description (String) 43 | TaskStatusId (Int32?) 44 | Updated (DateTime?) 45 | UpdatedBy (String) 46 | 47 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SimpleExample.DataLayer")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("SimpleExample.DataLayer")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("37aed239-5682-4540-a8ac-0e9cdfc09cd2")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/SimpleExample.DataLayer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {0C518694-411E-4AEB-9B33-6BD47548F16E} 8 | Library 9 | Properties 10 | SimpleExample.DataLayer 11 | SimpleExample.DataLayer 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\EntityFramework.Extras.0.9.4.0\lib\net40\EFUtil.Core.dll 35 | True 36 | 37 | 38 | ..\packages\EntityFramework.Extras.0.9.4.0\lib\net40\EFUtil.Repository.dll 39 | True 40 | 41 | 42 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 43 | True 44 | 45 | 46 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 47 | True 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | True 62 | True 63 | EFCodeFirstExample.tt 64 | 65 | 66 | 67 | True 68 | True 69 | StoredProcs.tt 70 | 71 | 72 | 73 | 74 | 75 | TextTemplatingFileGenerator 76 | EFCodeFirstExample.cs 77 | 78 | 79 | TextTemplatingFileGenerator 80 | ManualExample.txt 81 | 82 | 83 | 84 | TextTemplatingFileGenerator 85 | StoredProcs.cs 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | True 94 | True 95 | ManualExample.tt 96 | 97 | 98 | 99 | 106 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/StoredProcs.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by SqlSharpener. 4 | // 5 | // Changes to this file may cause incorrect behavior and will be lost if 6 | // the code is regenerated. 7 | // 8 | // ------------------------------------------------------------------------------ 9 | namespace SimpleExample.DataLayer 10 | { 11 | using System; 12 | using System.IO; 13 | using System.Linq; 14 | using System.Data; 15 | using System.Data.SqlClient; 16 | using System.Configuration; 17 | using System.Collections.Generic; 18 | using Microsoft.SqlServer.Server; 19 | 20 | /// 21 | /// Interface of the wrapper class for calling stored procedures. 22 | /// 23 | public partial interface IStoredProcedures 24 | { 25 | /// 26 | /// Calls the "usp_TaskCreate" stored procedure 27 | /// 28 | /// The number of rows affected. 29 | int TaskCreate( TaskCreateInputDto input ); 30 | 31 | /// 32 | /// Calls the "usp_TaskCreate" stored procedure using POCO objects 33 | /// 34 | /// The number of rows affected. 35 | TPocoOutputDto TaskCreate( IProcedureInputDto input ) 36 | where TPocoOutputDto : IProcedureOutputDto, new(); 37 | 38 | 39 | /// 40 | /// Calls the "usp_TaskCreate" stored procedure 41 | /// 42 | /// The number of rows affected. 43 | int TaskCreate( String Name, String Description, Int32? TaskStatusId, DateTime? Created, String CreatedBy, DateTime? Updated, String UpdatedBy, out Int32? TaskId ); 44 | 45 | /// 46 | /// Calls the "usp_TaskCreateMultiple" stored procedure 47 | /// 48 | /// An IEnumerable of id 49 | Result> TaskCreateMultiple( TaskCreateMultipleInputDto input ); 50 | 51 | /// 52 | /// Calls the "usp_TaskCreateMultiple" stored procedure using POCO objects 53 | /// 54 | /// An IEnumerable of id 55 | TPocoOutputDto TaskCreateMultiple( IProcedureInputDto input ) 56 | where TPocoOutputDto : IProcedureOutputDto>>, new(); 57 | 58 | /// 59 | /// Calls the "usp_TaskCreateMultiple" stored procedure using generated objects for table-valued parameters. 60 | /// 61 | /// An IEnumerable of id 62 | Result> TaskCreateMultiple( IEnumerable tasks ); 63 | 64 | /// 65 | /// Calls the "usp_TaskCreateMultiple" stored procedure 66 | /// 67 | /// An IEnumerable of id 68 | Result> TaskCreateMultiple( IEnumerable tasks ); 69 | 70 | /// 71 | /// Calls the "usp_TaskGet" stored procedure 72 | /// 73 | /// A DTO filled with the results of the SELECT statement. 74 | Result TaskGet( TaskGetInputDto input ); 75 | 76 | /// 77 | /// Calls the "usp_TaskGet" stored procedure using POCO objects 78 | /// 79 | /// A DTO filled with the results of the SELECT statement. 80 | TPocoOutputDto TaskGet( IProcedureInputDto input ) 81 | where TPocoOutputDto : IProcedureOutputDto>, new(); 82 | 83 | 84 | /// 85 | /// Calls the "usp_TaskGet" stored procedure 86 | /// 87 | /// A DTO filled with the results of the SELECT statement. 88 | Result TaskGet( Int32? TaskId ); 89 | 90 | /// 91 | /// Calls the "usp_TaskUpdate" stored procedure 92 | /// 93 | /// The number of rows affected. 94 | int TaskUpdate( TaskUpdateInputDto input ); 95 | 96 | /// 97 | /// Calls the "usp_TaskUpdate" stored procedure using POCO objects 98 | /// 99 | /// The number of rows affected. 100 | TPocoOutputDto TaskUpdate( IProcedureInputDto input ) 101 | where TPocoOutputDto : IProcedureOutputDto, new(); 102 | 103 | 104 | /// 105 | /// Calls the "usp_TaskUpdate" stored procedure 106 | /// 107 | /// The number of rows affected. 108 | int TaskUpdate( Int32? TaskId, String Name, String Description, Int32? TaskStatusId, DateTime? Updated, String UpdatedBy ); 109 | 110 | } 111 | 112 | /// 113 | /// Interface that a POCO can implement to be able to pass it in as the input DTO of a stored procedure 114 | /// if you prefer not to use the generated input dto. 115 | /// 116 | public partial interface IProcedureInputDto 117 | { 118 | /// 119 | /// Converts the property values of the POCO into an array of objects. 120 | /// The order of values in the array should match the parameters of the 121 | /// stored procedure (excluding any output parameters). 122 | /// 123 | object[] ToObjectArray(); 124 | 125 | /// 126 | /// Sets property values of the POCO with values from any output parameters 127 | /// of the stored procedure. Value will be passed in the same order as the 128 | /// output parameters appear in the stored procedure. 129 | /// 130 | void SetFromOutputParameters(object[] outputValues); 131 | } 132 | 133 | /// 134 | /// Interface that a POCO can implement to be used as the output DTO of a stored procedure 135 | /// if you prefer not to use the generated output dto. 136 | /// 137 | public partial interface IProcedureOutputDto 138 | { 139 | /// 140 | /// Sets property values of the POCO with values from any output parameters 141 | /// of the stored procedure. Value will be passed in the same order as the 142 | /// output parameters appear in the stored procedure. 143 | /// 144 | void SetFromResult(TGeneratedOutput result); 145 | } 146 | 147 | /// 148 | /// Interface that a POCO can implement to be able to pass it into a table-valued parameter 149 | /// if you prefer not to use the generated parameter dto. 150 | /// 151 | public partial interface ITableValuedParamRow 152 | { 153 | SqlDataRecord ToSqlDataRecord(); 154 | } 155 | 156 | /// 157 | /// Wrapper class for calling stored procedures. 158 | /// 159 | public partial class StoredProcedures : IStoredProcedures 160 | { 161 | private string connectionString; 162 | 163 | public StoredProcedures(string connectionString) 164 | { 165 | this.connectionString = connectionString; 166 | } 167 | 168 | 169 | /// 170 | /// Calls the "usp_TaskCreate" stored procedure using a generated input DTO 171 | /// 172 | /// The number of rows affected. 173 | public virtual int TaskCreate( TaskCreateInputDto input ) 174 | { 175 | Int32? TaskIdOutput; 176 | var result = this.TaskCreate(input.Name, input.Description, input.TaskStatusId, input.Created, input.CreatedBy, input.Updated, input.UpdatedBy, out TaskIdOutput); 177 | input.TaskId = TaskIdOutput; 178 | return result; 179 | } 180 | 181 | 182 | /// 183 | /// Calls the "usp_TaskCreate" stored procedure using POCO objects 184 | /// 185 | /// The number of rows affected. 186 | public virtual TPocoOutputDto TaskCreate( IProcedureInputDto input ) 187 | where TPocoOutputDto : IProcedureOutputDto, new() 188 | { 189 | var parameters = input.ToObjectArray(); 190 | Int32? TaskIdOutput; 191 | var result = this.TaskCreate((String)parameters[0], (String)parameters[1], (Int32?)parameters[2], (DateTime?)parameters[3], (String)parameters[4], (DateTime?)parameters[5], (String)parameters[6], out TaskIdOutput); 192 | var outputValues = new List(); 193 | outputValues.Add(TaskIdOutput); 194 | input.SetFromOutputParameters(outputValues.ToArray()); 195 | var outputPoco = new TPocoOutputDto(); 196 | outputPoco.SetFromResult(result); 197 | return outputPoco; 198 | } 199 | 200 | 201 | /// 202 | /// Calls the "usp_TaskCreate" stored procedure 203 | /// 204 | /// The number of rows affected. 205 | public virtual int TaskCreate( String Name, String Description, Int32? TaskStatusId, DateTime? Created, String CreatedBy, DateTime? Updated, String UpdatedBy, out Int32? TaskId ) 206 | { 207 | OnTaskCreateBegin(); 208 | int result; 209 | using(var conn = new SqlConnection(connectionString)) 210 | { 211 | conn.Open(); 212 | using (var cmd = conn.CreateCommand()) 213 | { 214 | cmd.CommandType = CommandType.StoredProcedure; 215 | cmd.CommandText = "usp_TaskCreate"; 216 | cmd.Parameters.Add("Name", SqlDbType.VarChar).Value = (object)Name ?? DBNull.Value; 217 | cmd.Parameters.Add("Description", SqlDbType.VarChar).Value = (object)Description ?? DBNull.Value; 218 | cmd.Parameters.Add("TaskStatusId", SqlDbType.Int).Value = (object)TaskStatusId ?? DBNull.Value; 219 | cmd.Parameters.Add("Created", SqlDbType.DateTime).Value = (object)Created ?? DBNull.Value; 220 | cmd.Parameters.Add("CreatedBy", SqlDbType.VarChar).Value = (object)CreatedBy ?? DBNull.Value; 221 | cmd.Parameters.Add("Updated", SqlDbType.DateTime).Value = (object)Updated ?? DBNull.Value; 222 | cmd.Parameters.Add("UpdatedBy", SqlDbType.VarChar).Value = (object)UpdatedBy ?? DBNull.Value; 223 | var TaskIdOutputParameter = new SqlParameter("TaskId", SqlDbType.Int) { Direction = ParameterDirection.Output }; 224 | cmd.Parameters.Add(TaskIdOutputParameter); 225 | 226 | result = cmd.ExecuteNonQuery(); 227 | TaskId = TaskIdOutputParameter.Value as Int32?; 228 | 229 | } 230 | conn.Close(); 231 | } 232 | OnTaskCreateEnd(result); 233 | return result; 234 | } 235 | 236 | partial void OnTaskCreateBegin(); 237 | partial void OnTaskCreateEnd(int result); 238 | 239 | /// 240 | /// Calls the "usp_TaskCreateMultiple" stored procedure using a generated input DTO 241 | /// 242 | /// An IEnumerable of id 243 | public virtual Result> TaskCreateMultiple( TaskCreateMultipleInputDto input ) 244 | { 245 | var result = this.TaskCreateMultiple(input.tasks); 246 | return result; 247 | } 248 | 249 | 250 | /// 251 | /// Calls the "usp_TaskCreateMultiple" stored procedure using POCO objects 252 | /// 253 | /// An IEnumerable of id 254 | public virtual TPocoOutputDto TaskCreateMultiple( IProcedureInputDto input ) 255 | where TPocoOutputDto : IProcedureOutputDto>>, new() 256 | { 257 | var parameters = input.ToObjectArray(); 258 | var result = this.TaskCreateMultiple((IEnumerable)parameters[0]); 259 | var outputValues = new List(); 260 | input.SetFromOutputParameters(outputValues.ToArray()); 261 | var outputPoco = new TPocoOutputDto(); 262 | outputPoco.SetFromResult(result); 263 | return outputPoco; 264 | } 265 | 266 | /// 267 | /// Calls the "usp_TaskCreateMultiple" stored procedure using generated objects for table-valued parameters. 268 | /// 269 | /// An IEnumerable of id 270 | public virtual Result> TaskCreateMultiple( IEnumerable tasks ) 271 | { 272 | return this.TaskCreateMultiple( (IEnumerable)tasks ); 273 | } 274 | 275 | /// 276 | /// Calls the "usp_TaskCreateMultiple" stored procedure 277 | /// 278 | /// An IEnumerable of id 279 | public virtual Result> TaskCreateMultiple( IEnumerable tasks ) 280 | { 281 | OnTaskCreateMultipleBegin(); 282 | Result> result = new Result>(); 283 | using(var conn = new SqlConnection(connectionString)) 284 | { 285 | conn.Open(); 286 | using (var cmd = conn.CreateCommand()) 287 | { 288 | cmd.CommandType = CommandType.StoredProcedure; 289 | cmd.CommandText = "usp_TaskCreateMultiple"; 290 | cmd.Parameters.Add("tasks", SqlDbType.Structured).Value = tasks.Select(s => s.ToSqlDataRecord()); 291 | 292 | using(var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) 293 | { 294 | result.RecordsAffected = reader.RecordsAffected; 295 | var list = new List(); 296 | while (reader.Read()) 297 | { 298 | Int32 item; 299 | item = reader.GetInt32(0); 300 | list.Add(item); 301 | } 302 | result.Data = list; 303 | reader.Close(); 304 | } 305 | 306 | } 307 | conn.Close(); 308 | } 309 | OnTaskCreateMultipleEnd(result); 310 | return result; 311 | } 312 | 313 | partial void OnTaskCreateMultipleBegin(); 314 | partial void OnTaskCreateMultipleEnd(Result> result); 315 | 316 | /// 317 | /// Calls the "usp_TaskGet" stored procedure using a generated input DTO 318 | /// 319 | /// A DTO filled with the results of the SELECT statement. 320 | public virtual Result TaskGet( TaskGetInputDto input ) 321 | { 322 | var result = this.TaskGet(input.TaskId); 323 | return result; 324 | } 325 | 326 | 327 | /// 328 | /// Calls the "usp_TaskGet" stored procedure using POCO objects 329 | /// 330 | /// A DTO filled with the results of the SELECT statement. 331 | public virtual TPocoOutputDto TaskGet( IProcedureInputDto input ) 332 | where TPocoOutputDto : IProcedureOutputDto>, new() 333 | { 334 | var parameters = input.ToObjectArray(); 335 | var result = this.TaskGet((Int32?)parameters[0]); 336 | var outputValues = new List(); 337 | input.SetFromOutputParameters(outputValues.ToArray()); 338 | var outputPoco = new TPocoOutputDto(); 339 | outputPoco.SetFromResult(result); 340 | return outputPoco; 341 | } 342 | 343 | 344 | /// 345 | /// Calls the "usp_TaskGet" stored procedure 346 | /// 347 | /// A DTO filled with the results of the SELECT statement. 348 | public virtual Result TaskGet( Int32? TaskId ) 349 | { 350 | OnTaskGetBegin(); 351 | Result result = new Result(); 352 | using(var conn = new SqlConnection(connectionString)) 353 | { 354 | conn.Open(); 355 | using (var cmd = conn.CreateCommand()) 356 | { 357 | cmd.CommandType = CommandType.StoredProcedure; 358 | cmd.CommandText = "usp_TaskGet"; 359 | cmd.Parameters.Add("TaskId", SqlDbType.Int).Value = (object)TaskId ?? DBNull.Value; 360 | 361 | using(var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) 362 | { 363 | result.RecordsAffected = reader.RecordsAffected; 364 | while (reader.Read()) 365 | { 366 | var item = new TaskGetOutputDto(); 367 | item.Name = reader.GetString(0); 368 | item.Description = reader.GetString(1); 369 | item.Status = reader.GetString(2); 370 | item.Created = reader.GetDateTime(3); 371 | item.CreatedBy = reader.GetString(4); 372 | item.Updated = reader.GetDateTime(5); 373 | item.UpdatedBy = reader.GetString(6); 374 | result.Data = item; 375 | } 376 | reader.Close(); 377 | } 378 | 379 | } 380 | conn.Close(); 381 | } 382 | OnTaskGetEnd(result); 383 | return result; 384 | } 385 | 386 | partial void OnTaskGetBegin(); 387 | partial void OnTaskGetEnd(Result result); 388 | 389 | /// 390 | /// Calls the "usp_TaskUpdate" stored procedure using a generated input DTO 391 | /// 392 | /// The number of rows affected. 393 | public virtual int TaskUpdate( TaskUpdateInputDto input ) 394 | { 395 | var result = this.TaskUpdate(input.TaskId, input.Name, input.Description, input.TaskStatusId, input.Updated, input.UpdatedBy); 396 | return result; 397 | } 398 | 399 | 400 | /// 401 | /// Calls the "usp_TaskUpdate" stored procedure using POCO objects 402 | /// 403 | /// The number of rows affected. 404 | public virtual TPocoOutputDto TaskUpdate( IProcedureInputDto input ) 405 | where TPocoOutputDto : IProcedureOutputDto, new() 406 | { 407 | var parameters = input.ToObjectArray(); 408 | var result = this.TaskUpdate((Int32?)parameters[0], (String)parameters[1], (String)parameters[2], (Int32?)parameters[3], (DateTime?)parameters[4], (String)parameters[5]); 409 | var outputValues = new List(); 410 | input.SetFromOutputParameters(outputValues.ToArray()); 411 | var outputPoco = new TPocoOutputDto(); 412 | outputPoco.SetFromResult(result); 413 | return outputPoco; 414 | } 415 | 416 | 417 | /// 418 | /// Calls the "usp_TaskUpdate" stored procedure 419 | /// 420 | /// The number of rows affected. 421 | public virtual int TaskUpdate( Int32? TaskId, String Name, String Description, Int32? TaskStatusId, DateTime? Updated, String UpdatedBy ) 422 | { 423 | OnTaskUpdateBegin(); 424 | int result; 425 | using(var conn = new SqlConnection(connectionString)) 426 | { 427 | conn.Open(); 428 | using (var cmd = conn.CreateCommand()) 429 | { 430 | cmd.CommandType = CommandType.StoredProcedure; 431 | cmd.CommandText = "usp_TaskUpdate"; 432 | cmd.Parameters.Add("TaskId", SqlDbType.Int).Value = (object)TaskId ?? DBNull.Value; 433 | cmd.Parameters.Add("Name", SqlDbType.VarChar).Value = (object)Name ?? DBNull.Value; 434 | cmd.Parameters.Add("Description", SqlDbType.VarChar).Value = (object)Description ?? DBNull.Value; 435 | cmd.Parameters.Add("TaskStatusId", SqlDbType.Int).Value = (object)TaskStatusId ?? DBNull.Value; 436 | cmd.Parameters.Add("Updated", SqlDbType.DateTime).Value = (object)Updated ?? DBNull.Value; 437 | cmd.Parameters.Add("UpdatedBy", SqlDbType.VarChar).Value = (object)UpdatedBy ?? DBNull.Value; 438 | 439 | result = cmd.ExecuteNonQuery(); 440 | 441 | } 442 | conn.Close(); 443 | } 444 | OnTaskUpdateEnd(result); 445 | return result; 446 | } 447 | 448 | partial void OnTaskUpdateBegin(); 449 | partial void OnTaskUpdateEnd(int result); 450 | 451 | 452 | /// 453 | /// Helper function to get the bytes out of varbinary columns 454 | /// 455 | private byte[] GetBytes(IDataReader reader, int ordinal) 456 | { 457 | MemoryStream ms = new MemoryStream(); 458 | BinaryWriter writer = new BinaryWriter(ms); 459 | byte[] buffer = new byte[1024]; 460 | long blobSize = reader.GetBytes(ordinal, 0, null, 0, 0); 461 | long currPos = 0; 462 | while (currPos < blobSize) { 463 | currPos += reader.GetBytes(ordinal, currPos, buffer, 0, 1024); 464 | writer.Write(buffer); 465 | writer.Flush(); 466 | } 467 | writer.Close(); 468 | return ms.ToArray(); 469 | } 470 | } 471 | 472 | /// 473 | /// The return value of the stored procedure functions. 474 | /// 475 | public partial class Result 476 | { 477 | public T Data { get; set; } 478 | public int RecordsAffected { get; set; } 479 | } 480 | 481 | /// 482 | /// DTO for the input of the "usp_TaskCreate" stored procedure. 483 | /// 484 | public partial class TaskCreateInputDto 485 | { 486 | /// 487 | /// Property that fills the Name input parameter. 488 | /// 489 | public String Name { get; set; } 490 | /// 491 | /// Property that fills the Description input parameter. 492 | /// 493 | public String Description { get; set; } 494 | /// 495 | /// Property that fills the TaskStatusId input parameter. 496 | /// 497 | public Int32? TaskStatusId { get; set; } 498 | /// 499 | /// Property that fills the Created input parameter. 500 | /// 501 | public DateTime? Created { get; set; } 502 | /// 503 | /// Property that fills the CreatedBy input parameter. 504 | /// 505 | public String CreatedBy { get; set; } 506 | /// 507 | /// Property that fills the Updated input parameter. 508 | /// 509 | public DateTime? Updated { get; set; } 510 | /// 511 | /// Property that fills the UpdatedBy input parameter. 512 | /// 513 | public String UpdatedBy { get; set; } 514 | /// 515 | /// Property that gets filled with the TaskId output parameter. 516 | /// 517 | public Int32? TaskId { get; internal set; } 518 | } 519 | 520 | 521 | /// 522 | /// DTO for the input of the "usp_TaskCreateMultiple" stored procedure. 523 | /// 524 | public partial class TaskCreateMultipleInputDto 525 | { 526 | /// 527 | /// Property that fills the tasks input parameter. 528 | /// 529 | public IEnumerable tasks { get; set; } 530 | } 531 | 532 | /// 533 | /// DTO for the input of the "tasks" table-valued parameter of the "usp_TaskCreateMultiple" stored procedure. 534 | /// 535 | public partial class TaskCreateMultiple_tasksParamDto : ITableValuedParamRow 536 | { 537 | public String Name { get; set; } 538 | public String Description { get; set; } 539 | public Int32? TaskStatusId { get; set; } 540 | public DateTime? Created { get; set; } 541 | public String CreatedBy { get; set; } 542 | public DateTime? Updated { get; set; } 543 | public String UpdatedBy { get; set; } 544 | 545 | public SqlDataRecord ToSqlDataRecord() 546 | { 547 | var sdr = new SqlDataRecord( 548 | new SqlMetaData("Name", SqlDbType.VarChar), 549 | new SqlMetaData("Description", SqlDbType.VarChar), 550 | new SqlMetaData("TaskStatusId", SqlDbType.Int), 551 | new SqlMetaData("Created", SqlDbType.DateTime), 552 | new SqlMetaData("CreatedBy", SqlDbType.VarChar), 553 | new SqlMetaData("Updated", SqlDbType.DateTime), 554 | new SqlMetaData("UpdatedBy", SqlDbType.VarChar) 555 | ); 556 | sdr.SetString(0, Name); 557 | sdr.SetString(1, Description); 558 | if(TaskStatusId.HasValue) sdr.SetInt32(2, TaskStatusId.GetValueOrDefault()); else sdr.SetDBNull(2); 559 | if(Created.HasValue) sdr.SetDateTime(3, Created.GetValueOrDefault()); else sdr.SetDBNull(3); 560 | sdr.SetString(4, CreatedBy); 561 | if(Updated.HasValue) sdr.SetDateTime(5, Updated.GetValueOrDefault()); else sdr.SetDBNull(5); 562 | sdr.SetString(6, UpdatedBy); 563 | return sdr; 564 | } 565 | } 566 | 567 | 568 | /// 569 | /// DTO for the input of the "usp_TaskGet" stored procedure. 570 | /// 571 | public partial class TaskGetInputDto 572 | { 573 | /// 574 | /// Property that fills the TaskId input parameter. 575 | /// 576 | public Int32? TaskId { get; set; } 577 | } 578 | 579 | /// 580 | /// DTO for the output of the "usp_TaskGet" stored procedure. 581 | /// 582 | public partial class TaskGetOutputDto 583 | { 584 | public String Name { get; set; } 585 | public String Description { get; set; } 586 | public String Status { get; set; } 587 | public DateTime Created { get; set; } 588 | public String CreatedBy { get; set; } 589 | public DateTime Updated { get; set; } 590 | public String UpdatedBy { get; set; } 591 | } 592 | 593 | 594 | /// 595 | /// DTO for the input of the "usp_TaskUpdate" stored procedure. 596 | /// 597 | public partial class TaskUpdateInputDto 598 | { 599 | /// 600 | /// Property that fills the TaskId input parameter. 601 | /// 602 | public Int32? TaskId { get; set; } 603 | /// 604 | /// Property that fills the Name input parameter. 605 | /// 606 | public String Name { get; set; } 607 | /// 608 | /// Property that fills the Description input parameter. 609 | /// 610 | public String Description { get; set; } 611 | /// 612 | /// Property that fills the TaskStatusId input parameter. 613 | /// 614 | public Int32? TaskStatusId { get; set; } 615 | /// 616 | /// Property that fills the Updated input parameter. 617 | /// 618 | public DateTime? Updated { get; set; } 619 | /// 620 | /// Property that fills the UpdatedBy input parameter. 621 | /// 622 | public String UpdatedBy { get; set; } 623 | } 624 | 625 | 626 | } 627 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/StoredProcs.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="true" language="C#" #> 2 | <#@ assembly name="$(SolutionDir)\packages\SqlSharpener.1.0.10\tools\SqlSharpener.dll" #> 3 | <#@ output extension=".cs" #> 4 | <#@ import namespace="Microsoft.VisualStudio.TextTemplating" #> 5 | <#@ import namespace="System.Collections.Generic" #> 6 | <#@ import namespace="SqlSharpener" #> 7 | <# 8 | // Ensure the SqlSharpener version number above matches the version you installed! 9 | 10 | // Specify paths to your *.sql files. Remember to include your tables as well! We need them to get the data types. 11 | var sqlPaths = new List(); 12 | sqlPaths.Add(Host.ResolvePath(@"..\SimpleExample.Database\dbo\Tables")); 13 | sqlPaths.Add(Host.ResolvePath(@"..\SimpleExample.Database\dbo\Types")); 14 | sqlPaths.Add(Host.ResolvePath(@"..\SimpleExample.Database\dbo\Stored Procedures")); 15 | 16 | // Set parameters for the template. 17 | var session = new TextTemplatingSession(); 18 | session["outputNamespace"] = "SimpleExample.DataLayer"; 19 | session["connectionStringVariableName"] = "ConnectionString1"; 20 | session["procedurePrefix"] = "usp_"; 21 | session["sqlPaths"] = sqlPaths; 22 | 23 | // Generate the code. 24 | var t = new SqlSharpener.StoredProceduresTemplate(); 25 | t.Session = session; 26 | t.Initialize(); 27 | this.Write(t.TransformText()); 28 | #> -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.DataLayer/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.Database/Database.sqlproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | Database 8 | 2.0 9 | 4.1 10 | {221efff5-dc8e-4e7f-8107-a5218f8fde81} 11 | Microsoft.Data.Tools.Schema.Sql.Sql120DatabaseSchemaProvider 12 | Database 13 | 14 | 15 | SimpleExample.Database 16 | SimpleExample.Database 17 | 1033, CI 18 | BySchemaAndSchemaType 19 | True 20 | v4.5 21 | CS 22 | Properties 23 | False 24 | True 25 | True 26 | 27 | 28 | bin\Release\ 29 | $(MSBuildProjectName).sql 30 | False 31 | pdbonly 32 | true 33 | false 34 | true 35 | prompt 36 | 4 37 | 38 | 39 | bin\Debug\ 40 | $(MSBuildProjectName).sql 41 | false 42 | true 43 | full 44 | false 45 | true 46 | true 47 | prompt 48 | 4 49 | 50 | 51 | 11.0 52 | 53 | True 54 | 11.0 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.Database/dbo/Stored Procedures/usp_TaskCreate.sql: -------------------------------------------------------------------------------- 1 | CREATE PROCEDURE [dbo].[usp_TaskCreate] 2 | @Name varchar(50), 3 | @Description varchar(1000), 4 | @TaskStatusId int, 5 | @Created datetime, 6 | @CreatedBy varchar(50), 7 | @Updated datetime, 8 | @UpdatedBy varchar(50), 9 | @TaskId int output 10 | AS 11 | INSERT INTO Tasks 12 | (Name, [Description], TaskStatusId, Created, CreatedBy, Updated, UpdatedBy) 13 | VALUES 14 | (@Name, @Description, @TaskStatusId, @Created, @CreatedBy, @Updated, @UpdatedBy) 15 | 16 | -- Output parameters are generated as C# "out" parameters. 17 | SET @TaskId = SCOPE_IDENTITY() 18 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.Database/dbo/Stored Procedures/usp_TaskCreateMultiple.sql: -------------------------------------------------------------------------------- 1 | CREATE PROCEDURE [dbo].[usp_TaskCreateMultiple] 2 | @tasks Tasks READONLY 3 | AS 4 | DECLARE @ids TABLE(id int) 5 | 6 | INSERT INTO Tasks 7 | (Name, [Description], TaskStatusId, Created, CreatedBy, Updated, UpdatedBy) 8 | OUTPUT inserted.Id into @ids 9 | SELECT 10 | Name, [Description], TaskStatusId, Created, CreatedBy, Updated, UpdatedBy 11 | FROM @tasks 12 | 13 | 14 | SELECT id from @ids -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.Database/dbo/Stored Procedures/usp_TaskGet.sql: -------------------------------------------------------------------------------- 1 | CREATE PROCEDURE [dbo].[usp_TaskGet] 2 | @TaskId int 3 | AS 4 | 5 | -- Specifying "TOP 1" makes the generated return value a single instance instead of an IEnumerable. 6 | SELECT TOP 1 7 | t.Name, 8 | t.[Description], 9 | ts.Name as [Status], 10 | t.Created, 11 | t.CreatedBy, 12 | t.Updated, 13 | t.UpdatedBy 14 | FROM Tasks t 15 | JOIN TaskStatus ts ON t.TaskStatusId = ts.Id 16 | WHERE t.Id = @TaskId 17 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.Database/dbo/Stored Procedures/usp_TaskUpdate.sql: -------------------------------------------------------------------------------- 1 | CREATE PROCEDURE [dbo].[usp_TaskUpdate] 2 | @TaskId int, 3 | @Name varchar(50), 4 | @Description varchar(1000), 5 | @TaskStatusId int, 6 | @Updated datetime, 7 | @UpdatedBy varchar(50) 8 | AS 9 | 10 | UPDATE Tasks 11 | SET 12 | Name = @Name, 13 | [Description] = @Description, 14 | TaskStatusId = @TaskStatusId, 15 | Updated = @Updated, 16 | UpdatedBy = @UpdatedBy 17 | WHERE 18 | Id = @TaskId 19 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.Database/dbo/Tables/TaskStatus.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [dbo].[TaskStatus] 2 | ( 3 | [Id] INT NOT NULL PRIMARY KEY, 4 | [Name] VARCHAR(50) NOT NULL 5 | ) 6 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.Database/dbo/Tables/Tasks.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [dbo].[Tasks] 2 | ( 3 | [Id] INT NOT NULL PRIMARY KEY IDENTITY, 4 | [Name] VARCHAR(50) NOT NULL, 5 | [Description] VARCHAR(1000) NOT NULL, 6 | [TaskStatusId] INT NOT NULL, 7 | [Created] DATETIME NOT NULL , 8 | [CreatedBy] VARCHAR(50) NOT NULL, 9 | [Updated] DATETIME NOT NULL, 10 | [UpdatedBy] VARCHAR(50) NOT NULL, 11 | CONSTRAINT [FK_Tasks_ToTaskStatus] FOREIGN KEY ([TaskStatusId]) REFERENCES [TaskStatus]([Id]) 12 | ) 13 | -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExample.Database/dbo/Types/Tasks.sql: -------------------------------------------------------------------------------- 1 | CREATE TYPE Tasks as TABLE( 2 | Name varchar(50), 3 | [Description] varchar(1000), 4 | TaskStatusId int, 5 | Created datetime, 6 | CreatedBy varchar(50), 7 | Updated datetime, 8 | UpdatedBy varchar(50) 9 | ) -------------------------------------------------------------------------------- /examples/SimpleExample/SimpleExamples.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "Database", "SimpleExample.Database\Database.sqlproj", "{221EFFF5-DC8E-4E7F-8107-A5218F8FDE81}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleExample.DataLayer", "SimpleExample.DataLayer\SimpleExample.DataLayer.csproj", "{0C518694-411E-4AEB-9B33-6BD47548F16E}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{C1C4C879-A0F4-4502-B617-C66639E18F79}" 11 | ProjectSection(SolutionItems) = preProject 12 | .nuget\packages.config = .nuget\packages.config 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {221EFFF5-DC8E-4E7F-8107-A5218F8FDE81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {221EFFF5-DC8E-4E7F-8107-A5218F8FDE81}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {221EFFF5-DC8E-4E7F-8107-A5218F8FDE81}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 24 | {221EFFF5-DC8E-4E7F-8107-A5218F8FDE81}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {221EFFF5-DC8E-4E7F-8107-A5218F8FDE81}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {221EFFF5-DC8E-4E7F-8107-A5218F8FDE81}.Release|Any CPU.Deploy.0 = Release|Any CPU 27 | {0C518694-411E-4AEB-9B33-6BD47548F16E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {0C518694-411E-4AEB-9B33-6BD47548F16E}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {0C518694-411E-4AEB-9B33-6BD47548F16E}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {0C518694-411E-4AEB-9B33-6BD47548F16E}.Release|Any CPU.Build.0 = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /examples/SimpleExample/packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml -------------------------------------------------------------------------------- /src/SqlSharpener.Tests/MetaBuilderTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace SqlSharpener.Tests 6 | { 7 | [TestClass] 8 | public class MetaBuilderTest 9 | { 10 | 11 | [TestMethod] 12 | public void TableTest() 13 | { 14 | var builder = new MetaBuilder(); 15 | builder.LoadModel("create table tb1(col1 int not null identity(1,1), col2 varchar(50) null, col3 decimal(5,3))"); 16 | 17 | Assert.AreEqual(1, builder.Tables.Count()); 18 | Assert.AreEqual("tb1", builder.Tables.First().Name); 19 | var columns = builder.Tables.First().Columns; 20 | Assert.AreEqual(3, columns.Count()); 21 | 22 | Assert.AreEqual("col1", columns.First().Name); 23 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 24 | Assert.AreEqual(true, columns.First().IsIdentity); 25 | Assert.AreEqual(false, columns.First().IsNullable); 26 | Assert.AreEqual(0, columns.First().Length); 27 | Assert.AreEqual(0, columns.First().Precision); 28 | Assert.AreEqual(0, columns.First().Scale); 29 | 30 | Assert.AreEqual("col2", columns.ElementAt(1).Name); 31 | Assert.AreEqual("String", columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 32 | Assert.AreEqual(false, columns.ElementAt(1).IsIdentity); 33 | Assert.AreEqual(true, columns.ElementAt(1).IsNullable); 34 | Assert.AreEqual(50, columns.ElementAt(1).Length); 35 | Assert.AreEqual(0, columns.ElementAt(1).Precision); 36 | Assert.AreEqual(0, columns.ElementAt(1).Scale); 37 | 38 | Assert.AreEqual("col3", columns.ElementAt(2).Name); 39 | Assert.AreEqual("Decimal?", columns.ElementAt(2).DataTypes[TypeFormat.DotNetFrameworkType]); 40 | Assert.AreEqual(false, columns.ElementAt(2).IsIdentity); 41 | Assert.AreEqual(true, columns.ElementAt(2).IsNullable); 42 | Assert.AreEqual(0, columns.ElementAt(2).Length); 43 | Assert.AreEqual(5, columns.ElementAt(2).Precision); 44 | Assert.AreEqual(3, columns.ElementAt(2).Scale); 45 | } 46 | 47 | [TestMethod] 48 | public void SingleFunctionCallTest() 49 | { 50 | var builder = new MetaBuilder(); 51 | builder.LoadModel( 52 | "create table tb1(col1 int)", 53 | "create procedure blah as insert into tb1 (col1) values (3) select cast(scope_identity() as float)"); 54 | Assert.AreEqual(1, builder.Procedures.Count()); 55 | Assert.AreEqual("blah", builder.Procedures.First().Name); 56 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 57 | Assert.AreEqual(1, builder.Procedures.First().Selects.First().Columns.Count()); 58 | } 59 | 60 | [TestMethod] 61 | public void SingleVariableTest() 62 | { 63 | var builder = new MetaBuilder(); 64 | builder.LoadModel( 65 | "create table tb1(id int identity(1,1), col1 int)", 66 | "create procedure blah as insert into tb1 (col1) values (3) declare @id int = scope_identity() select @id"); 67 | Assert.AreEqual(1, builder.Procedures.Count()); 68 | Assert.AreEqual("blah", builder.Procedures.First().Name); 69 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 70 | Assert.AreEqual(1, builder.Procedures.First().Selects.First().Columns.Count()); 71 | Assert.AreEqual("id", builder.Procedures.First().Selects.First().Columns.First().Name); 72 | Assert.AreEqual("Object", builder.Procedures.First().Selects.First().Columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 73 | Assert.AreEqual(true, builder.Procedures.First().Selects.First().Columns.First().IsNullable); 74 | } 75 | 76 | [TestMethod] 77 | public void SingleColumnTest() 78 | { 79 | var builder = new MetaBuilder(); 80 | builder.LoadModel( 81 | "create table tb1(col1 int)", 82 | "create procedure blah as select col1 from tb1"); 83 | Assert.AreEqual(1, builder.Procedures.Count()); 84 | Assert.AreEqual("blah", builder.Procedures.First().Name); 85 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 86 | var columns = builder.Procedures.First().Selects.First().Columns; 87 | Assert.AreEqual(1, columns.Count()); 88 | Assert.AreEqual("col1", columns.First().Name); 89 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 90 | Assert.AreEqual("Int32", columns.First().DataTypes[TypeFormat.DbTypeEnum]); 91 | } 92 | 93 | [TestMethod] 94 | public void SingleColumnAliasTest() 95 | { 96 | var builder = new MetaBuilder(); 97 | builder.LoadModel( 98 | "create table tb1(col1 int)", 99 | "create procedure blah as select col1 as c1 from tb1"); 100 | Assert.AreEqual(1, builder.Procedures.Count()); 101 | Assert.AreEqual("blah", builder.Procedures.First().Name); 102 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 103 | var columns = builder.Procedures.First().Selects.First().Columns; 104 | Assert.AreEqual(1, columns.Count()); 105 | Assert.AreEqual("c1", columns.First().Name); 106 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 107 | Assert.AreEqual("Int32", columns.First().DataTypes[TypeFormat.DbTypeEnum]); 108 | } 109 | 110 | [TestMethod] 111 | public void DoubleColumnTest() 112 | { 113 | var builder = new MetaBuilder(); 114 | builder.LoadModel( 115 | "create table tb1(col1 int, col2 varchar(50))", 116 | "create procedure blah as select col1, col2 from tb1"); 117 | Assert.AreEqual(1, builder.Procedures.Count()); 118 | Assert.AreEqual("blah", builder.Procedures.First().Name); 119 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 120 | var columns = builder.Procedures.First().Selects.First().Columns; 121 | Assert.AreEqual(2, columns.Count()); 122 | Assert.AreEqual("col1", columns.First().Name); 123 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 124 | Assert.AreEqual("Int32", columns.First().DataTypes[TypeFormat.DbTypeEnum]); 125 | Assert.AreEqual("col2", columns.ElementAt(1).Name); 126 | Assert.AreEqual("String", columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 127 | Assert.AreEqual("String", columns.ElementAt(1).DataTypes[TypeFormat.DbTypeEnum]); 128 | } 129 | 130 | [TestMethod] 131 | public void SingleRowTest() 132 | { 133 | var builder = new MetaBuilder(); 134 | builder.LoadModel( 135 | "create table tb1(col1 int)", 136 | "create procedure blah as select top 1 col1 from tb1"); 137 | Assert.AreEqual(1, builder.Procedures.Count()); 138 | Assert.AreEqual("blah", builder.Procedures.First().Name); 139 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 140 | var columns = builder.Procedures.First().Selects.First().Columns; 141 | Assert.AreEqual(1, columns.Count()); 142 | Assert.AreEqual("col1", columns.First().Name); 143 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 144 | Assert.AreEqual("Int32", columns.First().DataTypes[TypeFormat.DbTypeEnum]); 145 | Assert.AreEqual(true, builder.Procedures.First().Selects.First().IsSingleRow); 146 | } 147 | 148 | [TestMethod] 149 | public void MultipleTableTest() 150 | { 151 | var builder = new MetaBuilder(); 152 | builder.LoadModel( 153 | "create table tb1(id int, col1 int)", 154 | "create table tb2(tb1Id int, col1 varchar(50))", 155 | "create procedure blah as select tb1.col1, tb2.col1 as col2 from tb1 join tb2 on tb1.id = tb2.tb1Id"); 156 | Assert.AreEqual(1, builder.Procedures.Count()); 157 | Assert.AreEqual("blah", builder.Procedures.First().Name); 158 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 159 | var columns = builder.Procedures.First().Selects.First().Columns; 160 | Assert.AreEqual(2, columns.Count()); 161 | Assert.AreEqual("col1", columns.First().Name); 162 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 163 | Assert.AreEqual("Int32", columns.First().DataTypes[TypeFormat.DbTypeEnum]); 164 | Assert.AreEqual("col2", columns.ElementAt(1).Name); 165 | Assert.AreEqual("String", columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 166 | Assert.AreEqual("String", columns.ElementAt(1).DataTypes[TypeFormat.DbTypeEnum]); 167 | } 168 | 169 | [TestMethod] 170 | public void MultipleTableAliasTest() 171 | { 172 | var builder = new MetaBuilder(); 173 | builder.LoadModel( 174 | "create table tb1(id int, col1 int)", 175 | "create table tb2(tb1Id int, col1 varchar(50))", 176 | "create procedure blah as select t1.col1, t2.col1 as col2 from tb1 as t1 join tb2 as t2 on t1.id = t2.tb1Id"); 177 | Assert.AreEqual(1, builder.Procedures.Count()); 178 | Assert.AreEqual("blah", builder.Procedures.First().Name); 179 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 180 | var columns = builder.Procedures.First().Selects.First().Columns; 181 | Assert.AreEqual(2, columns.Count()); 182 | Assert.AreEqual("col1", columns.First().Name); 183 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 184 | Assert.AreEqual("Int32", columns.First().DataTypes[TypeFormat.DbTypeEnum]); 185 | Assert.AreEqual("col2", columns.ElementAt(1).Name); 186 | Assert.AreEqual("String", columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 187 | Assert.AreEqual("String", columns.ElementAt(1).DataTypes[TypeFormat.DbTypeEnum]); 188 | } 189 | 190 | [TestMethod] 191 | public void MultipleSelectTest() 192 | { 193 | var builder = new MetaBuilder(); 194 | builder.LoadModel( 195 | "create table tb1(id int, col1 int)", 196 | "create table tb2(tb1Id int, col1 varchar(50))", 197 | "create procedure blah as select t1.col1, t2.col1 as col2 from tb1 as t1 join tb2 as t2 on t1.id = t2.tb1Id \n select t1.col1, t2.col1 as col2 from tb1 as t1 join tb2 as t2 on t1.id = t2.tb1Id"); 198 | Assert.AreEqual(1, builder.Procedures.Count()); 199 | Assert.AreEqual("blah", builder.Procedures.First().Name); 200 | Assert.AreEqual(2, builder.Procedures.First().Selects.Count()); 201 | var columns = builder.Procedures.First().Selects.First().Columns; 202 | Assert.AreEqual(2, columns.Count()); 203 | Assert.AreEqual("col1", columns.First().Name); 204 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 205 | Assert.AreEqual("Int32", columns.First().DataTypes[TypeFormat.DbTypeEnum]); 206 | Assert.AreEqual("col2", columns.ElementAt(1).Name); 207 | Assert.AreEqual("String", columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 208 | Assert.AreEqual("String", columns.ElementAt(1).DataTypes[TypeFormat.DbTypeEnum]); 209 | } 210 | 211 | [TestMethod] 212 | public void TableValueTest() 213 | { 214 | var builder = new MetaBuilder(); 215 | builder.LoadModel( 216 | "create type tbInput as table(id int not null, col1 int null)", 217 | "create procedure blah (@tbInput tbInput READONLY) as select col1 from @tbInput"); 218 | Assert.AreEqual(1, builder.Procedures.Count()); 219 | var proc = builder.Procedures.First(); 220 | Assert.AreEqual("blah", proc.Name); 221 | Assert.AreEqual(1, proc.Parameters.Count()); 222 | var param = proc.Parameters.First(); 223 | Assert.AreEqual("tbInput", param.Name); 224 | Assert.AreEqual(false, param.IsOutput); 225 | Assert.AreEqual(null, param.DataTypes); 226 | Assert.AreEqual("tbInput", param.TableValue.Name); 227 | Assert.AreEqual(2, param.TableValue.Columns.Count()); 228 | Assert.AreEqual("id", param.TableValue.Columns.First().Name); 229 | Assert.AreEqual(false, param.TableValue.Columns.First().IsIdentity); 230 | Assert.AreEqual(false, param.TableValue.Columns.First().IsNullable); 231 | Assert.AreEqual("Int32?", param.TableValue.Columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 232 | Assert.AreEqual("col1", param.TableValue.Columns.ElementAt(1).Name); 233 | Assert.AreEqual(false, param.TableValue.Columns.ElementAt(1).IsIdentity); 234 | Assert.AreEqual(true, param.TableValue.Columns.ElementAt(1).IsNullable); 235 | Assert.AreEqual("Int32?", param.TableValue.Columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 236 | } 237 | 238 | [TestMethod] 239 | public void UnionSelectTest() 240 | { 241 | var builder = new MetaBuilder(); 242 | builder.LoadModel( 243 | "create table tb1(id1 int, col1 varchar(50))", 244 | "create table tb2(id2 int, col2 varchar(50))", 245 | "create table tb3(id3 int, col3 varchar(50))", 246 | "create procedure blah as select id1, col1 from tb1 union select id2, col2 from tb2 union select id3, col3 from tb3"); 247 | Assert.AreEqual(1, builder.Procedures.Count()); 248 | var proc = builder.Procedures.First(); 249 | Assert.AreEqual("blah", proc.Name); 250 | Assert.AreEqual(0, proc.Parameters.Count()); 251 | Assert.AreEqual(1, proc.Selects.Count()); 252 | var select = proc.Selects.First(); 253 | Assert.AreEqual(2, select.Columns.Count()); 254 | Assert.AreEqual("id1", select.Columns.First().Name); 255 | Assert.AreEqual("col1", select.Columns.ElementAt(1).Name); 256 | } 257 | 258 | [TestMethod] 259 | public void LeftJoinTest() 260 | { 261 | var builder = new MetaBuilder(); 262 | builder.LoadModel( 263 | "create table tb1(id int, col1 int not null)", 264 | "create table tb2(tb1Id int, col2 int not null)", 265 | "create procedure blah as select col1, col2 from tb1 left join tb2 on tb1.id = tb2.tb1Id"); 266 | Assert.AreEqual(1, builder.Procedures.Count()); 267 | Assert.AreEqual("blah", builder.Procedures.First().Name); 268 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 269 | var columns = builder.Procedures.First().Selects.First().Columns; 270 | Assert.AreEqual(2, columns.Count()); 271 | Assert.AreEqual("col1", columns.First().Name); 272 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 273 | Assert.AreEqual(false, columns.First().IsNullable); 274 | Assert.AreEqual("col2", columns.ElementAt(1).Name); 275 | Assert.AreEqual("Int32?", columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 276 | Assert.AreEqual(true, columns.ElementAt(1).IsNullable); 277 | } 278 | 279 | [TestMethod] 280 | public void LeftJoinWithAliasesTest() 281 | { 282 | var builder = new MetaBuilder(); 283 | builder.LoadModel( 284 | "create table tb1(id int, col1 int not null)", 285 | "create table tb2(tb1Id int, col2 int not null)", 286 | "create procedure blah as select t1.col1, t2.col2 from tb1 t1 left join tb2 t2 on t1.id = t2.tb1Id"); 287 | Assert.AreEqual(1, builder.Procedures.Count()); 288 | Assert.AreEqual("blah", builder.Procedures.First().Name); 289 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 290 | var columns = builder.Procedures.First().Selects.First().Columns; 291 | Assert.AreEqual(2, columns.Count()); 292 | Assert.AreEqual("col1", columns.First().Name); 293 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 294 | Assert.AreEqual(false, columns.First().IsNullable); 295 | Assert.AreEqual("col2", columns.ElementAt(1).Name); 296 | Assert.AreEqual("Int32?", columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 297 | Assert.AreEqual(true, columns.ElementAt(1).IsNullable); 298 | } 299 | 300 | [TestMethod] 301 | public void RightJoinTest() 302 | { 303 | var builder = new MetaBuilder(); 304 | builder.LoadModel( 305 | "create table tb1(id int, col1 int not null)", 306 | "create table tb2(tb1Id int, col2 int not null)", 307 | "create procedure blah as select col1, col2 from tb1 right join tb2 on tb1.id = tb2.tb1Id"); 308 | Assert.AreEqual(1, builder.Procedures.Count()); 309 | Assert.AreEqual("blah", builder.Procedures.First().Name); 310 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 311 | var columns = builder.Procedures.First().Selects.First().Columns; 312 | Assert.AreEqual(2, columns.Count()); 313 | Assert.AreEqual("col1", columns.First().Name); 314 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 315 | Assert.AreEqual(true, columns.First().IsNullable); 316 | Assert.AreEqual("col2", columns.ElementAt(1).Name); 317 | Assert.AreEqual("Int32?", columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 318 | Assert.AreEqual(false, columns.ElementAt(1).IsNullable); 319 | } 320 | 321 | [TestMethod] 322 | public void LeftJoinToInnerJoinSetTest() 323 | { 324 | var builder = new MetaBuilder(); 325 | builder.LoadModel( 326 | "create table tb1(id int, col1 int not null)", 327 | "create table tb2(id int, col2 int not null)", 328 | "create table tb3(id int, col3 int not null)", 329 | "create procedure blah as select col1, col2, col3 from tb1 left join tb2 join tb3 on tb2.id = tb3.id on tb1.id = tb2.id"); 330 | Assert.AreEqual(1, builder.Procedures.Count()); 331 | Assert.AreEqual("blah", builder.Procedures.First().Name); 332 | Assert.AreEqual(1, builder.Procedures.First().Selects.Count()); 333 | var columns = builder.Procedures.First().Selects.First().Columns; 334 | Assert.AreEqual(3, columns.Count()); 335 | Assert.AreEqual("col1", columns.First().Name); 336 | Assert.AreEqual("Int32?", columns.First().DataTypes[TypeFormat.DotNetFrameworkType]); 337 | Assert.AreEqual(false, columns.First().IsNullable); 338 | Assert.AreEqual("col2", columns.ElementAt(1).Name); 339 | Assert.AreEqual("Int32?", columns.ElementAt(1).DataTypes[TypeFormat.DotNetFrameworkType]); 340 | Assert.AreEqual(true, columns.ElementAt(1).IsNullable); 341 | Assert.AreEqual("col3", columns.ElementAt(2).Name); 342 | Assert.AreEqual("Int32?", columns.ElementAt(2).DataTypes[TypeFormat.DotNetFrameworkType]); 343 | Assert.AreEqual(true, columns.ElementAt(2).IsNullable); 344 | } 345 | 346 | [TestMethod] 347 | public void PrimaryForeignKeyTest() 348 | { 349 | var builder = new MetaBuilder(); 350 | builder.LoadModel( 351 | @"create table dbo.tb1(id int identity(1,1) not null, 352 | CONSTRAINT [PK_id] PRIMARY KEY CLUSTERED ([id] ASC))", 353 | @"create table dbo.tb2(id int identity(1,1) not null, tb1Id int not null, 354 | CONSTRAINT [PK_id] PRIMARY KEY CLUSTERED ([id] ASC), 355 | CONSTRAINT [FK_tb2_tb1] FOREIGN KEY ([tb1Id]) REFERENCES [dbo].[tb1] ([id]))"); 356 | Assert.AreEqual(2, builder.Tables.Count()); 357 | Assert.AreEqual("tb1", builder.Tables.First().Name); 358 | 359 | Assert.AreEqual(1, builder.Tables.First().Columns.Count()); 360 | Assert.AreEqual(true, builder.Tables.First().Columns.First().IsPrimaryKey); 361 | Assert.AreEqual(false, builder.Tables.First().Columns.First().IsForeignKey); 362 | Assert.AreEqual(0, builder.Tables.First().Columns.First().ParentRelationships.Count()); 363 | Assert.AreEqual(1, builder.Tables.First().Columns.First().ChildRelationships.Count()); 364 | Assert.AreEqual(null, builder.Tables.First().Columns.First().ChildRelationships.First().Database); 365 | Assert.AreEqual("dbo", builder.Tables.First().Columns.First().ChildRelationships.First().Schema); 366 | Assert.AreEqual("tb2", builder.Tables.First().Columns.First().ChildRelationships.First().TableOrView); 367 | Assert.AreEqual("tb1Id", builder.Tables.First().Columns.First().ChildRelationships.First().Columns.First()); 368 | 369 | Assert.AreEqual(2, builder.Tables.ElementAt(1).Columns.Count()); 370 | Assert.AreEqual(true, builder.Tables.ElementAt(1).Columns.First().IsPrimaryKey); 371 | Assert.AreEqual(false, builder.Tables.ElementAt(1).Columns.First().IsForeignKey); 372 | Assert.AreEqual(false, builder.Tables.ElementAt(1).Columns.ElementAt(1).IsPrimaryKey); 373 | Assert.AreEqual(true, builder.Tables.ElementAt(1).Columns.ElementAt(1).IsForeignKey); 374 | Assert.AreEqual(0, builder.Tables.ElementAt(1).Columns.First().ParentRelationships.Count()); 375 | Assert.AreEqual(0, builder.Tables.ElementAt(1).Columns.First().ChildRelationships.Count()); 376 | Assert.AreEqual(1, builder.Tables.ElementAt(1).Columns.ElementAt(1).ParentRelationships.Count()); 377 | Assert.AreEqual(0, builder.Tables.ElementAt(1).Columns.ElementAt(1).ChildRelationships.Count()); 378 | Assert.AreEqual(null, builder.Tables.ElementAt(1).Columns.ElementAt(1).ParentRelationships.First().Database); 379 | Assert.AreEqual("dbo", builder.Tables.ElementAt(1).Columns.ElementAt(1).ParentRelationships.First().Schema); 380 | Assert.AreEqual("tb1", builder.Tables.ElementAt(1).Columns.ElementAt(1).ParentRelationships.First().TableOrView); 381 | Assert.AreEqual("id", builder.Tables.ElementAt(1).Columns.ElementAt(1).ParentRelationships.First().Columns.First()); 382 | } 383 | 384 | [TestMethod] 385 | public void ViewTest() 386 | { 387 | var builder = new MetaBuilder(); 388 | 389 | builder.LoadModel( 390 | @"create table [dbo].[tb1] ([Id] smallint identity (1, 1) not null,[Name] varchar (50) not null, CONSTRAINT [PK_tb1] PRIMARY KEY CLUSTERED ([Id] ASC))", 391 | @"create view [dbo].[view1] AS SELECT * FROM [dbo].[tb1] WHERE [Id] > 0"); 392 | 393 | Assert.AreEqual(1, builder.Tables.Count()); 394 | Assert.AreEqual(2, builder.Tables.First().Columns.Count()); 395 | Assert.AreEqual(1, builder.Views.Count()); 396 | Assert.AreEqual(2, builder.Views.First().Columns.Count()); 397 | } 398 | 399 | [TestMethod] 400 | public void ViewWithExpressionTest() 401 | { 402 | var builder = new MetaBuilder(); 403 | 404 | builder.LoadModel( 405 | @"create table [dbo].[tb1] ([Id] smallint identity (1, 1) not null,[FirstName] varchar (50) not null, [LastName] varchar (50) not null,CONSTRAINT [PK_tb1] PRIMARY KEY CLUSTERED ([Id] ASC))", 406 | @"create view [dbo].[view1] AS SELECT [Name] = [FirstName] + ' ' + [LastName] FROM [dbo].[tb1] WHERE [Id] > 0"); 407 | 408 | Assert.AreEqual(1, builder.Tables.Count()); 409 | Assert.AreEqual(3, builder.Tables.First().Columns.Count()); 410 | Assert.AreEqual(1, builder.Views.Count()); 411 | Assert.AreEqual(1, builder.Views.First().Columns.Count()); 412 | } 413 | } 414 | } 415 | -------------------------------------------------------------------------------- /src/SqlSharpener.Tests/ProcedureHelperTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System.Collections.Generic; 4 | using SqlSharpener.Model; 5 | 6 | namespace SqlSharpener.Tests 7 | { 8 | [TestClass] 9 | public class ProcedureHelperTest 10 | { 11 | private IDictionary tableAliases; 12 | 13 | [TestInitialize] 14 | public void Initialize() 15 | { 16 | tableAliases = new Dictionary{ 17 | { "t1", "tb1" }, 18 | { "t2", "tb2" } 19 | }; 20 | } 21 | 22 | [TestMethod] 23 | public void ReturnTypeSingleRowSingleColumnTest() 24 | { 25 | // Arrange 26 | var helper = new ProcedureHelper(); 27 | var procedure = new Procedure("proc", "proc", null, null, new List{ 46 | new Select(new List{ 47 | new SelectColumn("col1", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Int32?"), true), 48 | new SelectColumn("col2", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Int32"), false), 49 | new SelectColumn("col3", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "String"), true) 50 | }, true, null) 51 | }); 52 | 53 | // Act 54 | var result = helper.GetReturnType(procedure); 55 | 56 | // Assert 57 | Assert.AreEqual("Result", result); 58 | } 59 | 60 | [TestMethod] 61 | public void ReturnTypeMultipleRowSingleColumnTest() 62 | { 63 | // Arrange 64 | var helper = new ProcedureHelper(); 65 | var procedure = new Procedure("proc", "proc", null, null, new List{ 84 | new Select(new List{ 85 | new SelectColumn("col1", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Int32?"), true), 86 | new SelectColumn("col2", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "String"), true) 87 | }, false, null) 88 | }); 89 | 90 | // Act 91 | var result = helper.GetReturnType(procedure); 92 | 93 | // Assert 94 | Assert.AreEqual("Result>", result); 95 | } 96 | 97 | [TestMethod] 98 | public void ReturnTypeMultipleSelectTest() 99 | { 100 | // Arrange 101 | var helper = new ProcedureHelper(); 102 | var procedure = new Procedure("proc", "proc", null, null, new List{ 126 | new Select(new List{ 127 | new SelectColumn("col1", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Int32?"), true), 128 | new SelectColumn("col2", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "String"), true) 129 | }, false, null) 130 | }); 131 | 132 | // Act 133 | var result = helper.GetReturnVariable(procedure); 134 | 135 | // Assert 136 | Assert.AreEqual("Result> result = new Result>();", result); 137 | } 138 | 139 | [TestMethod] 140 | public void ReturnVariableMultipleSelectTest() 141 | { 142 | // Arrange 143 | var helper = new ProcedureHelper(); 144 | var procedure = new Procedure("proc", "proc", null, null, new List{ 233 | new Select(new List{ 234 | new SelectColumn("col1", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Int32?"), true) 235 | }, true, null) 236 | }); 237 | 238 | // Act 239 | var result = helper.GetDtoObject(procedure); 240 | 241 | // Assert 242 | Assert.AreEqual("", result); 243 | } 244 | 245 | [TestMethod] 246 | public void DTOObjectSingleSelectSingleRowMultipleColumnTest() 247 | { 248 | // Arrange 249 | var helper = new ProcedureHelper(); 250 | var procedure = new Procedure("proc", "proc", null, null, new List{ 281 | new Select(new List{ 282 | new SelectColumn("col1", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Int32?"), true) 283 | }, false, null) 284 | }); 285 | 286 | // Act 287 | var result = helper.GetDtoObject(procedure); 288 | 289 | // Assert 290 | Assert.AreEqual("", result); 291 | } 292 | 293 | [TestMethod] 294 | public void DTOObjectSingleSelectMultipleRowMultipleColumnTest() 295 | { 296 | // Arrange 297 | var helper = new ProcedureHelper(); 298 | var procedure = new Procedure("proc", "proc", null, null, new List{ 327 | new Select(new List{ 328 | new SelectColumn("col1", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Int32?"), false) 329 | }, true, null) 330 | }); 331 | 332 | // Act 333 | var result = helper.GetExecuteStatement(procedure); 334 | 335 | // Assert 336 | Assert.AreEqual("result = (Int32)cmd.ExecuteScalar();\r\n", result); 337 | } 338 | 339 | [TestMethod] 340 | public void ExecuteStatementNoSelectTest() 341 | { 342 | // Arrange 343 | var helper = new ProcedureHelper(); 344 | var procedure = new Procedure("proc", "proc", null, null, null); 345 | 346 | // Act 347 | var result = helper.GetExecuteStatement(procedure); 348 | 349 | // Assert 350 | Assert.AreEqual("result = cmd.ExecuteNonQuery();\r\n", result); 351 | } 352 | 353 | [TestMethod] 354 | public void ExecuteStatementSingleRowMulipleColumnTest() 355 | { 356 | // Arrange 357 | var helper = new ProcedureHelper(); 358 | var procedure = new Procedure("proc", "proc", null, null, new List{ 390 | new Select(new List{ 391 | new SelectColumn("col1", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Int32?"), true), 392 | new SelectColumn("col2", DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "String"), true), 393 | }, false, null) 394 | }); 395 | 396 | // Act 397 | var result = helper.GetExecuteStatement(procedure); 398 | 399 | // Assert 400 | Assert.AreEqual(@"using(var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) 401 | { 402 | result.RecordsAffected = reader.RecordsAffected; 403 | var list = new List(); 404 | while (reader.Read()) 405 | { 406 | var item = new procOutputDto(); 407 | item.col1 = !reader.IsDBNull(0) ? reader.GetInt32(0) : default(Int32?); 408 | item.col2 = !reader.IsDBNull(1) ? reader.GetString(1) : default(String); 409 | list.Add(item); 410 | } 411 | result.Data = list; 412 | reader.Close(); 413 | } 414 | ", result); 415 | } 416 | 417 | [TestMethod] 418 | public void ExecuteStatementMultipleSelectTest() 419 | { 420 | // Arrange 421 | var helper = new ProcedureHelper(); 422 | var procedure = new Procedure("proc", "proc", null, null, new List selects) 28 | { 29 | this.Name = name; 30 | this.RawName = rawName; 31 | this.Prefix = prefix ?? ""; 32 | this.Parameters = parameters ?? new List(); 33 | this.Selects = selects ?? new List Selects { get; private set; } 110 | 111 | private QuerySpecification GetQueryFromUnion(BinaryQueryExpression binaryQueryExpression) 112 | { 113 | while (binaryQueryExpression.FirstQueryExpression as BinaryQueryExpression != null) 114 | { 115 | binaryQueryExpression = binaryQueryExpression.FirstQueryExpression as BinaryQueryExpression; 116 | } 117 | return binaryQueryExpression.FirstQueryExpression as QuerySpecification; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/SqlSharpener/Model/RelationshipIdentifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace SqlSharpener.Model 8 | { 9 | public class RelationshipIdentifier 10 | { 11 | public string Database { get; set; } 12 | public string Schema { get; set; } 13 | public string TableOrView { get; set; } 14 | public IEnumerable Columns { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/SqlSharpener/Model/Select.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SqlServer.TransactSql.ScriptDom; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace SqlSharpener.Model 8 | { 9 | /// 10 | /// Represents a SELECT statement in a stored procedure. 11 | /// 12 | [Serializable] 13 | public class Select 14 | { 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The columns. 19 | /// if set to true the select statement uses a TOP 1 clause or is a function call. 20 | /// The table aliases. 21 | public Select(IEnumerable columns, bool isSingleRow, IDictionary tableAliases) 22 | { 23 | this.Columns = columns ?? new List(); 24 | this.IsSingleRow = isSingleRow; 25 | this.TableAliases = tableAliases ?? new Dictionary(); 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// The query specification. 32 | /// The body column types. 33 | public Select(QuerySpecification querySpecification, IDictionary bodyColumnTypes) 34 | { 35 | // Get any table aliases. 36 | var aliasResolutionVisitor = new AliasResolutionVisitor(); 37 | querySpecification.Accept(aliasResolutionVisitor); 38 | this.TableAliases = aliasResolutionVisitor.Aliases; 39 | 40 | var outerJoinedTables = new List(); 41 | if (querySpecification.FromClause != null) 42 | { 43 | foreach (var join in querySpecification.FromClause.TableReferences.OfType()) 44 | { 45 | FillOuterJoins(outerJoinedTables, join, false); 46 | } 47 | } 48 | 49 | var topInt = querySpecification.TopRowFilter != null ? querySpecification.TopRowFilter.Expression as IntegerLiteral : null; 50 | this.IsSingleRow = topInt != null && topInt.Value == "1" && querySpecification.TopRowFilter.Percent == false; 51 | this.Columns = querySpecification.SelectElements.OfType().Select(x => new SelectColumn(x, bodyColumnTypes, this.TableAliases, outerJoinedTables)).ToList(); 52 | } 53 | 54 | /// 55 | /// Traverses the joins and gets a list of tables that have been outer joined. 56 | /// 57 | /// The outer joined tables list. 58 | /// The qualified join. 59 | /// if set to true a parent join was outer joined. 60 | private void FillOuterJoins(List outerJoinedTables, QualifiedJoin qualifiedJoin, bool isParentOuterJoined) 61 | { 62 | var tableReferences = new List(); 63 | if (qualifiedJoin.QualifiedJoinType == QualifiedJoinType.LeftOuter) 64 | { 65 | if (isParentOuterJoined) tableReferences.Add(qualifiedJoin.FirstTableReference); 66 | tableReferences.Add(qualifiedJoin.SecondTableReference); 67 | } 68 | else if (qualifiedJoin.QualifiedJoinType == QualifiedJoinType.RightOuter) 69 | { 70 | if (isParentOuterJoined) tableReferences.Add(qualifiedJoin.SecondTableReference); 71 | tableReferences.Add(qualifiedJoin.FirstTableReference); 72 | } 73 | else if (qualifiedJoin.QualifiedJoinType == QualifiedJoinType.FullOuter || qualifiedJoin.QualifiedJoinType == QualifiedJoinType.Inner) 74 | { 75 | if (isParentOuterJoined) 76 | { 77 | tableReferences.Add(qualifiedJoin.FirstTableReference); 78 | tableReferences.Add(qualifiedJoin.SecondTableReference); 79 | } 80 | } 81 | 82 | foreach (var tableReference in tableReferences) 83 | { 84 | var nestedQualifiedJoin = tableReference as QualifiedJoin; 85 | var namedTableReference = tableReference as NamedTableReference; 86 | if (nestedQualifiedJoin != null) 87 | { 88 | FillOuterJoins(outerJoinedTables, nestedQualifiedJoin, true); 89 | } 90 | else if (namedTableReference != null) 91 | { 92 | var aliasOrName = namedTableReference.Alias != null && !string.IsNullOrEmpty(namedTableReference.Alias.Value) 93 | ? namedTableReference.Alias.Value 94 | : namedTableReference.SchemaObject.BaseIdentifier.Value; 95 | outerJoinedTables.Add(aliasOrName); 96 | } 97 | } 98 | } 99 | 100 | /// 101 | /// Gets the columns. 102 | /// 103 | /// 104 | /// The columns. 105 | /// 106 | public IEnumerable Columns { get; private set; } 107 | 108 | /// 109 | /// Gets a value indicating whether this SELECT uses a TOP 1 clause or is a function call. 110 | /// 111 | /// 112 | /// true if this instance uses a TOP 1 clause or is a function call; otherwise, false. 113 | /// 114 | public bool IsSingleRow { get; private set; } 115 | 116 | /// 117 | /// Gets the table aliases. 118 | /// 119 | /// 120 | /// The table aliases. 121 | /// 122 | public IDictionary TableAliases { get; private set; } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/SqlSharpener/Model/SelectColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SqlServer.TransactSql.ScriptDom; 2 | using dac = Microsoft.SqlServer.Dac.Model; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Microsoft.SqlServer.Dac; 8 | 9 | namespace SqlSharpener.Model 10 | { 11 | /// 12 | /// Represents a column in a SELECT statement in a stored procedure. 13 | /// 14 | [Serializable] 15 | public class SelectColumn 16 | { 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The name or alias. 21 | /// The data types. 22 | /// if set to true [is nullable]. 23 | public SelectColumn(string name, IDictionary dataTypes, bool isNullable) 24 | { 25 | this.Name = name; 26 | this.DataTypes = dataTypes ?? new Dictionary(); 27 | this.IsNullable = isNullable; 28 | } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The select scalar expression. 34 | /// The body column types. 35 | /// The table aliases. 36 | /// The aliases or names of tables that were outer joined. Used to determine if a non-nulllable column could still be null. 37 | /// Could not find column within BodyDependencies: + fullColName 38 | public SelectColumn(SelectScalarExpression selectScalarExpression, IDictionary bodyColumnTypes, IDictionary tableAliases, IEnumerable outerJoinedTables) 39 | { 40 | if (selectScalarExpression.Expression is ColumnReferenceExpression) 41 | { 42 | var columnReferenceExpression = (ColumnReferenceExpression)selectScalarExpression.Expression; 43 | var identifiers = columnReferenceExpression.MultiPartIdentifier.Identifiers; 44 | var fullColName = this.GetFullColumnName(tableAliases, identifiers); 45 | 46 | this.Name = selectScalarExpression.ColumnName != null && selectScalarExpression.ColumnName.Value != null 47 | ? selectScalarExpression.ColumnName.Value 48 | : identifiers.Last().Value; 49 | 50 | var key = bodyColumnTypes.Keys.FirstOrDefault(x => x.EndsWith(fullColName, StringComparison.InvariantCultureIgnoreCase)); 51 | if (key == null) throw new InvalidOperationException("Could not find column within BodyDependencies: " + fullColName); 52 | 53 | 54 | bool outerJoined = false; 55 | // If the column was defined in the SELECT with the table alias or name, check if the table was outer joined. 56 | if (identifiers.Count() > 1) 57 | { 58 | var tableAliasOrName = identifiers.ElementAt(identifiers.Count() - 2).Value; 59 | outerJoined = outerJoinedTables.Contains(tableAliasOrName); 60 | } 61 | else // If the column was defined in the SELECT without any qualification, then there must 62 | // be only one column in the list of tables with that name. Look it up in the bodyColumnTypes. 63 | { 64 | var keyParts = key.Split('.'); 65 | if (keyParts.Count() > 1) 66 | { 67 | var tableAliasOrName = keyParts.ElementAt(keyParts.Count() - 2); 68 | outerJoined = outerJoinedTables.Contains(tableAliasOrName); 69 | } 70 | } 71 | 72 | var bodyColumnType = bodyColumnTypes[key]; 73 | this.DataTypes = bodyColumnType.Map; 74 | this.IsNullable = bodyColumnType.Nullable || outerJoined; 75 | } 76 | else if (selectScalarExpression.Expression is ConvertCall) 77 | { 78 | var convertCall = (ConvertCall)selectScalarExpression.Expression; 79 | this.Name = selectScalarExpression.ColumnName != null && selectScalarExpression.ColumnName.Value != null 80 | ? selectScalarExpression.ColumnName.Value 81 | : "Value"; 82 | this.DataTypes = DataTypeHelper.Instance.GetMap(TypeFormat.SqlServerDbType, convertCall.DataType.Name.BaseIdentifier.Value); 83 | this.IsNullable = true; 84 | } 85 | else if (selectScalarExpression.Expression is CastCall) 86 | { 87 | var castCall = (CastCall)selectScalarExpression.Expression; 88 | this.Name = selectScalarExpression.ColumnName != null && selectScalarExpression.ColumnName.Value != null 89 | ? selectScalarExpression.ColumnName.Value 90 | : "Value"; 91 | this.DataTypes = DataTypeHelper.Instance.GetMap(TypeFormat.SqlServerDbType, castCall.DataType.Name.BaseIdentifier.Value); 92 | this.IsNullable = true; 93 | } 94 | else if (selectScalarExpression.Expression is IntegerLiteral) 95 | { 96 | var integerLiteral = (IntegerLiteral)selectScalarExpression.Expression; 97 | this.Name = selectScalarExpression.ColumnName != null && selectScalarExpression.ColumnName.Value != null 98 | ? selectScalarExpression.ColumnName.Value 99 | : "Value"; 100 | this.DataTypes = DataTypeHelper.Instance.GetMap(TypeFormat.SqlServerDbType, "int"); 101 | this.IsNullable = true; 102 | } 103 | else if (selectScalarExpression.Expression is VariableReference) 104 | { 105 | var variableReference = (VariableReference)selectScalarExpression.Expression; 106 | this.Name = variableReference.Name.TrimStart('@'); 107 | this.DataTypes = DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Object"); 108 | this.IsNullable = true; 109 | } 110 | else 111 | { 112 | this.Name = selectScalarExpression.ColumnName != null && selectScalarExpression.ColumnName.Value != null 113 | ? selectScalarExpression.ColumnName.Value 114 | : "Value"; 115 | this.DataTypes = DataTypeHelper.Instance.GetMap(TypeFormat.DotNetFrameworkType, "Object"); 116 | this.IsNullable = true; 117 | } 118 | } 119 | 120 | /// 121 | /// Gets the name or alias. 122 | /// 123 | /// 124 | /// The name or alias. 125 | /// 126 | public string Name { get; private set; } 127 | 128 | /// 129 | /// Gets the data types. 130 | /// 131 | /// 132 | /// The data types. 133 | /// 134 | public IDictionary DataTypes { get; private set; } 135 | 136 | /// 137 | /// Gets or sets a value indicating whether this instance is nullable. 138 | /// 139 | /// 140 | /// true if this instance is nullable; otherwise, false. 141 | /// 142 | public bool IsNullable { get; set; } 143 | 144 | /// 145 | /// Gets the fully qualified column name with any table aliases resolved. 146 | /// 147 | /// The table aliases. 148 | /// The identifiers in the MultiPartIdentifier. 149 | /// 150 | /// The fully qualified column name. 151 | /// 152 | private string GetFullColumnName(IDictionary tableAliases, IList identifiers) 153 | { 154 | var list = identifiers.Select(x => x.Value).ToArray(); 155 | if (list.Count() > 1) 156 | { 157 | var tableIdentifier = list.ElementAt(list.Count() - 2); 158 | if (tableAliases.Keys.Any(x => x == tableIdentifier)) 159 | { 160 | list[list.Count() - 2] = tableAliases[tableIdentifier]; 161 | } 162 | } 163 | return string.Join(".", list); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/SqlSharpener/Model/Table.cs: -------------------------------------------------------------------------------- 1 | using dac = Microsoft.SqlServer.Dac.Model; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Microsoft.SqlServer.TransactSql.ScriptDom; 8 | using Microsoft.SqlServer.Dac; 9 | 10 | namespace SqlSharpener.Model 11 | { 12 | /// 13 | /// Represents a table in the model. 14 | /// 15 | [Serializable] 16 | public class Table 17 | { 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The name of the table. 22 | /// The columns. 23 | public Table(string name, IEnumerable columns) 24 | { 25 | this.Name = name; 26 | this.Columns = columns ?? new List(); 27 | } 28 | 29 | /// 30 | /// Initializes a new instance of the class. 31 | /// 32 | /// The TSqlObject representing the table. 33 | /// The primary keys. 34 | /// The foreign keys. 35 | public Table(dac.TSqlObject tSqlObject, IEnumerable primaryKeys, IDictionary> foreignKeys) 36 | { 37 | // Get the name. 38 | this.Name = tSqlObject.Name.Parts.Last(); 39 | 40 | // Get the columns 41 | var columns = new List(); 42 | var sqlColumns = tSqlObject.ObjectType.Name == "TableType" ? tSqlObject.GetReferenced(dac.TableType.Columns) : tSqlObject.GetReferenced(dac.Table.Columns); 43 | foreach (var sqlColumn in sqlColumns) 44 | { 45 | var column = new Column(sqlColumn, tSqlObject, primaryKeys, foreignKeys); 46 | columns.Add(column); 47 | } 48 | this.Columns = columns; 49 | } 50 | 51 | /// 52 | /// Gets the name of the table. 53 | /// 54 | /// 55 | /// The name of the table. 56 | /// 57 | public string Name { get; private set; } 58 | 59 | /// 60 | /// Gets the columns. 61 | /// 62 | /// 63 | /// The columns. 64 | /// 65 | public IEnumerable Columns { get; private set; } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/SqlSharpener/Model/View.cs: -------------------------------------------------------------------------------- 1 | using dac = Microsoft.SqlServer.Dac.Model; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Microsoft.SqlServer.TransactSql.ScriptDom; 8 | 9 | namespace SqlSharpener.Model 10 | { 11 | /// 12 | /// Represents a view in the model. 13 | /// 14 | [Serializable] 15 | public class View 16 | { 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The name of the view. 21 | /// The columns. 22 | public View(string name, IEnumerable columns) 23 | { 24 | this.Name = name; 25 | this.Columns = columns ?? new List(); 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// The TSqlObject representing the view. 32 | /// The primary keys. 33 | /// The foreign keys. 34 | public View(dac.TSqlObject tSqlObject, IEnumerable primaryKeys, IDictionary> foreignKeys) 35 | { 36 | // Get the name. 37 | this.Name = tSqlObject.Name.Parts.Last(); 38 | 39 | // Get the columns 40 | var columns = new List(); 41 | var sqlColumns = tSqlObject.GetReferenced(dac.View.Columns); 42 | foreach (var sqlColumn in sqlColumns) 43 | { 44 | var column = new Column(sqlColumn, tSqlObject, primaryKeys, foreignKeys); 45 | columns.Add(column); 46 | } 47 | this.Columns = columns; 48 | } 49 | 50 | /// 51 | /// Gets the name of the view. 52 | /// 53 | /// 54 | /// The name of the view. 55 | /// 56 | public string Name { get; private set; } 57 | 58 | /// 59 | /// Gets the columns. 60 | /// 61 | /// 62 | /// The columns. 63 | /// 64 | public IEnumerable Columns { get; private set; } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/SqlSharpener/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SqlSharpener")] 9 | [assembly: AssemblyDescription("Parses SQL files to create a meta-object hierarchy with which you can generate C# code such as stored procedure wrappers.")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Adam Eslinger")] 12 | [assembly: AssemblyProduct("SqlSharpener")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a4af30c7-1a1a-444e-a0fb-86d30dfd24f5")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/SqlSharpener/SelectVisitor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SqlServer.TransactSql.ScriptDom; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace SqlSharpener 9 | { 10 | [Serializable] 11 | internal class SelectVisitor : TSqlFragmentVisitor 12 | { 13 | public SelectVisitor() 14 | { 15 | this.Nodes = new List(); 16 | } 17 | 18 | public List Nodes { get; private set; } 19 | 20 | public override void Visit(SelectStatement node) 21 | { 22 | base.Visit(node); 23 | this.Nodes.Add(node.QueryExpression); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/SqlSharpener/SqlSharpener.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EF5B5FB1-4E44-491F-A50D-951F95674C04} 8 | Library 9 | Properties 10 | SqlSharpener 11 | SqlSharpener 12 | v4.6.1 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | bin\Debug\SqlSharpener.XML 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Microsoft.SqlServer.DACFx.12.0.2603.2\lib\Microsoft.Data.Tools.Contracts.dll 37 | True 38 | 39 | 40 | ..\packages\Microsoft.SqlServer.DacFx.x64.130.3485.1\lib\net40\Microsoft.Data.Tools.Schema.Sql.dll 41 | True 42 | 43 | 44 | ..\packages\Microsoft.SqlServer.DACFx.12.0.2603.2\lib\Microsoft.Data.Tools.Schema.Tasks.Sql.dll 45 | True 46 | 47 | 48 | ..\packages\Microsoft.SqlServer.DACFx.12.0.2603.2\lib\Microsoft.Data.Tools.Schema.Utilities.Sql.dll 49 | True 50 | 51 | 52 | ..\packages\Microsoft.SqlServer.DacFx.x64.130.3485.1\lib\net40\Microsoft.Data.Tools.Utilities.dll 53 | True 54 | 55 | 56 | ..\packages\Microsoft.SqlServer.DacFx.x64.130.3485.1\lib\net40\Microsoft.SqlServer.Dac.dll 57 | True 58 | 59 | 60 | ..\packages\Microsoft.SqlServer.DacFx.x64.130.3485.1\lib\net40\Microsoft.SqlServer.Dac.Extensions.dll 61 | True 62 | 63 | 64 | ..\packages\Microsoft.SqlServer.TransactSql.ScriptDom.13.0.1700.77\lib\net40\Microsoft.SqlServer.TransactSql.ScriptDom.dll 65 | True 66 | 67 | 68 | ..\packages\Microsoft.SqlServer.DacFx.x64.130.3485.1\lib\net40\Microsoft.SqlServer.Types.dll 69 | True 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | True 96 | True 97 | StoredProceduresTemplate.tt 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | TextTemplatingFilePreprocessor 108 | StoredProceduresTemplate.cs 109 | 110 | 111 | 112 | 119 | -------------------------------------------------------------------------------- /src/SqlSharpener/StoredProceduresTemplate.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="false" language="C#" #> 2 | <#@ assembly name="System.Core" #> 3 | <#@ import namespace="System.Linq" #> 4 | <#@ import namespace="System.Text" #> 5 | <#@ import namespace="System.Collections.Generic" #> 6 | <#@ output extension=".cs" #> 7 | <#@ parameter name="outputNamespace" type="System.String" #> 8 | <#@ parameter name="procedurePrefix" type="System.String" #> 9 | <#@ parameter name="sqlPaths" type="System.Collections.Generic.List" #> 10 | <# 11 | // This creates a pre-compiled template that can be called from 12 | // within a project to generate C# wrappers for stored procedures. 13 | 14 | var helper = new ProcedureHelper(); 15 | var meta = new MetaBuilder(sqlPaths.ToArray()); 16 | meta.ProcedurePrefix = procedurePrefix ?? ""; 17 | 18 | /////////////////Begin Template////////////////// 19 | #> 20 | // ------------------------------------------------------------------------------ 21 | // 22 | // This code was generated by SqlSharpener. 23 | // 24 | // Changes to this file may cause incorrect behavior and will be lost if 25 | // the code is regenerated. 26 | // 27 | // ------------------------------------------------------------------------------ 28 | namespace <#=helper.GetNamespace(outputNamespace)#> 29 | { 30 | using System; 31 | using System.IO; 32 | using System.Linq; 33 | using System.Data; 34 | using System.Data.SqlClient; 35 | using System.Configuration; 36 | using System.Collections.Generic; 37 | using Microsoft.SqlServer.Server; 38 | 39 | /// 40 | /// Interface of the wrapper class for calling stored procedures. 41 | /// 42 | public partial interface IStoredProcedures 43 | { 44 | <#foreach(var proc in meta.Procedures){ #> 45 | /// 46 | /// Calls the "<#=proc.RawName#>" stored procedure 47 | /// 48 | /// <#=helper.GetReturnXmlComment(proc)#> 49 | <#=helper.GetReturnType(proc)#> <#=proc.Name#>( <#=proc.Name#>InputDto input ); 50 | 51 | /// 52 | /// Calls the "<#=proc.RawName#>" stored procedure using POCO objects 53 | /// 54 | /// <#=helper.GetReturnXmlComment(proc)#> 55 | TPocoOutputDto <#=proc.Name#>( IProcedureInputDto input ) 56 | where TPocoOutputDto : IProcedureOutputDto<<#=helper.GetReturnType(proc)#>>, new(); 57 | 58 | <# if(proc.Parameters.Any(x => x.IsTableValue)) { #> 59 | /// 60 | /// Calls the "<#=proc.RawName#>" stored procedure using generated objects for table-valued parameters. 61 | /// 62 | /// <#=helper.GetReturnXmlComment(proc)#> 63 | <#=helper.GetReturnType(proc)#> <#=proc.Name#>( <#=helper.GetMethodParamList(proc, false, true, false)#> ); 64 | <# } #> 65 | 66 | /// 67 | /// Calls the "<#=proc.RawName#>" stored procedure 68 | /// 69 | /// <#=helper.GetReturnXmlComment(proc)#> 70 | <#=helper.GetReturnType(proc)#> <#=proc.Name#>( <#=helper.GetMethodParamList(proc, true, true, false)#> ); 71 | 72 | <# } #> 73 | } 74 | 75 | /// 76 | /// Interface that a POCO can implement to be able to pass it in as the input DTO of a stored procedure 77 | /// if you prefer not to use the generated input dto. 78 | /// 79 | public partial interface IProcedureInputDto 80 | { 81 | /// 82 | /// Converts the property values of the POCO into an array of objects. 83 | /// The order of values in the array should match the parameters of the 84 | /// stored procedure (excluding any output parameters). 85 | /// 86 | object[] ToObjectArray(); 87 | 88 | /// 89 | /// Sets property values of the POCO with values from any output parameters 90 | /// of the stored procedure. Value will be passed in the same order as the 91 | /// output parameters appear in the stored procedure. 92 | /// 93 | void SetFromOutputParameters(object[] outputValues); 94 | } 95 | 96 | /// 97 | /// Interface that a POCO can implement to be used as the output DTO of a stored procedure 98 | /// if you prefer not to use the generated output dto. 99 | /// 100 | public partial interface IProcedureOutputDto 101 | { 102 | /// 103 | /// Sets property values of the POCO with values from any output parameters 104 | /// of the stored procedure. Value will be passed in the same order as the 105 | /// output parameters appear in the stored procedure. 106 | /// 107 | void SetFromResult(TGeneratedOutput result); 108 | } 109 | 110 | /// 111 | /// Interface that a POCO can implement to be able to pass it into a table-valued parameter 112 | /// if you prefer not to use the generated parameter dto. 113 | /// 114 | public partial interface ITableValuedParamRow 115 | { 116 | SqlDataRecord ToSqlDataRecord(); 117 | } 118 | 119 | /// 120 | /// Wrapper class for calling stored procedures. 121 | /// 122 | public partial class StoredProcedures : IStoredProcedures 123 | { 124 | private string connectionString; 125 | 126 | public StoredProcedures(string connectionString) 127 | { 128 | this.connectionString = connectionString; 129 | } 130 | 131 | 132 | <#foreach(var proc in meta.Procedures){ #> 133 | /// 134 | /// Calls the "<#=proc.RawName#>" stored procedure using a generated input DTO 135 | /// 136 | /// <#=helper.GetReturnXmlComment(proc)#> 137 | public virtual <#=helper.GetReturnType(proc)#> <#=proc.Name#>( <#=proc.Name#>InputDto input ) 138 | { 139 | <# foreach(var outputParam in proc.Parameters.Where(x => x.IsOutput)){ #> 140 | <#=outputParam.DataTypes[TypeFormat.DotNetFrameworkType]#> <#=outputParam.Name#>Output; 141 | <# } #> 142 | var result = this.<#=proc.Name#>(<#=helper.GetMethodParamListForInputDto(proc)#>); 143 | <# foreach(var outputParam in proc.Parameters.Where(x => x.IsOutput)){ #> 144 | input.<#=outputParam.Name#> = <#=outputParam.Name#>Output; 145 | <# } #> 146 | return result; 147 | } 148 | 149 | 150 | /// 151 | /// Calls the "<#=proc.RawName#>" stored procedure using POCO objects 152 | /// 153 | /// <#=helper.GetReturnXmlComment(proc)#> 154 | public virtual TPocoOutputDto <#=proc.Name#>( IProcedureInputDto input ) 155 | where TPocoOutputDto : IProcedureOutputDto<<#=helper.GetReturnType(proc)#>>, new() 156 | { 157 | var parameters = input.ToObjectArray(); 158 | <# foreach(var outputParam in proc.Parameters.Where(x => x.IsOutput)){ #> 159 | <#=outputParam.DataTypes[TypeFormat.DotNetFrameworkType]#> <#=outputParam.Name#>Output; 160 | <# } #> 161 | var result = this.<#=proc.Name#>(<#=helper.GetMethodParamListForObjectArray(proc)#>); 162 | var outputValues = new List(); 163 | <# foreach(var outputParam in proc.Parameters.Where(x => x.IsOutput)){ #> 164 | outputValues.Add(<#=outputParam.Name#>Output); 165 | <# } #> 166 | input.SetFromOutputParameters(outputValues.ToArray()); 167 | var outputPoco = new TPocoOutputDto(); 168 | outputPoco.SetFromResult(result); 169 | return outputPoco; 170 | } 171 | 172 | <# if(proc.Parameters.Any(x => x.IsTableValue)) { #> 173 | /// 174 | /// Calls the "<#=proc.RawName#>" stored procedure using generated objects for table-valued parameters. 175 | /// 176 | /// <#=helper.GetReturnXmlComment(proc)#> 177 | public virtual <#=helper.GetReturnType(proc)#> <#=proc.Name#>( <#=helper.GetMethodParamList(proc, false, true, false)#> ) 178 | { 179 | return this.<#=proc.Name#>( <#=helper.GetMethodParamList(proc, true, true, true)#> ); 180 | } 181 | <# } #> 182 | 183 | /// 184 | /// Calls the "<#=proc.RawName#>" stored procedure 185 | /// 186 | /// <#=helper.GetReturnXmlComment(proc)#> 187 | public virtual <#=helper.GetReturnType(proc)#> <#=proc.Name#>( <#=helper.GetMethodParamList(proc, true, true, false)#> ) 188 | { 189 | On<#=proc.Name#>Begin(); 190 | <#=helper.GetReturnVariable(proc)#> 191 | using(var conn = new SqlConnection(connectionString)) 192 | { 193 | conn.Open(); 194 | using (var cmd = conn.CreateCommand()) 195 | { 196 | cmd.CommandType = CommandType.StoredProcedure; 197 | cmd.CommandText = "<#=proc.RawName#>"; 198 | <#=helper.GetSqlParamList(proc, 5)#> 199 | <#=helper.GetExecuteStatement(proc, 5)#> 200 | } 201 | conn.Close(); 202 | } 203 | On<#=proc.Name#>End(result); 204 | return result; 205 | } 206 | 207 | partial void On<#=proc.Name#>Begin(); 208 | partial void On<#=proc.Name#>End(<#=helper.GetReturnType(proc)#> result); 209 | 210 | <# } #> 211 | 212 | /// 213 | /// Helper function to get the bytes out of varbinary columns 214 | /// 215 | private byte[] GetBytes(IDataReader reader, int ordinal) 216 | { 217 | MemoryStream ms = new MemoryStream(); 218 | BinaryWriter writer = new BinaryWriter(ms); 219 | byte[] buffer = new byte[1024]; 220 | long blobSize = reader.GetBytes(ordinal, 0, null, 0, 0); 221 | long currPos = 0; 222 | while (currPos < blobSize) { 223 | currPos += reader.GetBytes(ordinal, currPos, buffer, 0, 1024); 224 | writer.Write(buffer); 225 | writer.Flush(); 226 | } 227 | writer.Close(); 228 | return ms.ToArray(); 229 | } 230 | } 231 | 232 | /// 233 | /// The return value of the stored procedure functions. 234 | /// 235 | public partial class Result 236 | { 237 | public T Data { get; set; } 238 | public int RecordsAffected { get; set; } 239 | } 240 | 241 | <#foreach(var proc in meta.Procedures){ #> 242 | <#=helper.GetDtoObject(proc, 1)#> 243 | <# } #> 244 | } 245 | -------------------------------------------------------------------------------- /src/SqlSharpener/TextBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace SqlSharpener 8 | { 9 | internal class TextBuilder 10 | { 11 | private int indent = 0; 12 | 13 | public TextBuilder() 14 | { 15 | this.StringBuilder = new StringBuilder(); 16 | } 17 | 18 | public StringBuilder StringBuilder { get; set; } 19 | 20 | public void Indent(int times = 1) 21 | { 22 | indent = indent + times; 23 | } 24 | 25 | public void Unindent() 26 | { 27 | if (indent > 0) indent--; 28 | } 29 | 30 | public void ClearIndent() 31 | { 32 | indent = 0; 33 | } 34 | 35 | public TextBuilder Append(string s) 36 | { 37 | this.AppendIndent(); 38 | this.StringBuilder.Append(s); 39 | return this; 40 | } 41 | 42 | public TextBuilder AppendFormat(string format, string s) 43 | { 44 | this.AppendIndent(); 45 | this.StringBuilder.AppendFormat(format, s); 46 | return this; 47 | } 48 | 49 | public TextBuilder AppendFormat(string format, string s1, string s2) 50 | { 51 | this.AppendIndent(); 52 | this.StringBuilder.AppendFormat(format, s1, s2); 53 | return this; 54 | } 55 | 56 | public TextBuilder AppendFormat(string format, string s1, string s2, string s3) 57 | { 58 | this.AppendIndent(); 59 | this.StringBuilder.AppendFormat(format, s1, s2, s3); 60 | return this; 61 | } 62 | 63 | public TextBuilder AppendFormat(string format, string s1, string s2, string s3, string s4) 64 | { 65 | this.AppendIndent(); 66 | this.StringBuilder.AppendFormat(format, s1, s2, s3, s4); 67 | return this; 68 | } 69 | 70 | public TextBuilder AppendFormatLine(string format, string s) 71 | { 72 | this.AppendFormat(format, s); 73 | this.StringBuilder.AppendLine(); 74 | return this; 75 | } 76 | 77 | public TextBuilder AppendFormatLine(string format, string s1, string s2) 78 | { 79 | this.AppendFormat(format, s1, s2); 80 | this.StringBuilder.AppendLine(); 81 | return this; 82 | } 83 | 84 | public TextBuilder AppendFormatLine(string format, string s1, string s2, string s3) 85 | { 86 | this.AppendFormat(format, s1, s2, s3); 87 | this.StringBuilder.AppendLine(); 88 | return this; 89 | } 90 | 91 | public TextBuilder AppendFormatLine(string format, string s1, string s2, string s3, string s4) 92 | { 93 | this.AppendFormat(format, s1, s2, s3, s4); 94 | this.StringBuilder.AppendLine(); 95 | return this; 96 | } 97 | 98 | public TextBuilder AppendLine() 99 | { 100 | this.AppendIndent(); 101 | this.StringBuilder.AppendLine(); 102 | return this; 103 | } 104 | 105 | public TextBuilder AppendLine(string s) 106 | { 107 | this.AppendIndent(); 108 | this.StringBuilder.AppendLine(s); 109 | return this; 110 | } 111 | 112 | public override string ToString() 113 | { 114 | return this.StringBuilder.ToString(); 115 | } 116 | 117 | private void AppendIndent() 118 | { 119 | if (indent > 0) 120 | { 121 | var tabs = new String('\t', indent); 122 | this.StringBuilder.Append(tabs); 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/SqlSharpener/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/SqlSharpener/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | --------------------------------------------------------------------------------