├── .gitignore ├── .vs └── Poco.Sql.NetCore │ └── v15 │ └── sqlite3 │ └── storage.ide ├── LICENSE ├── Logo.png ├── Poco.Sql.NetCore.Demo ├── Poco.Sql.NetCore.Demo.csproj ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── Poco.Sql.NetCore.Test.Models ├── Helper.cs ├── Mappings │ ├── OrderMap.cs │ ├── UserMap.cs │ └── VUserMap.cs ├── Order.cs ├── Poco.Sql.NetCore.Test.Models.csproj ├── Properties │ └── AssemblyInfo.cs ├── SuperUser.cs ├── User.cs └── VUser.cs ├── Poco.Sql.NetCore.UnitTests ├── Poco.Sql.NetCore.UnitTests.csproj ├── PocoSqlTests.cs └── UnitTestsRunner.cs ├── Poco.Sql.NetCore.sln ├── Poco.Sql.NetCore ├── Configuration.cs ├── Exceptions │ ├── CantUpdateVirtualException.cs │ └── NoSqlBuilderTaskFound.cs ├── Helpers │ └── ExpressionEvaluator.cs ├── Interfaces │ ├── IPocoSqlMapping.cs │ └── IRelationshipMap.cs ├── Poco.Sql.NetCore.csproj ├── PocoSqlCostomMapping.cs ├── PocoSqlExtensions.cs ├── PocoSqlMapping.cs ├── PocoSqlStoredProcedureMap.cs ├── PocoSqlStoredProcedureMapping.cs ├── PocoSqlStoredProceduresMapping.cs ├── Properties │ └── AssemblyInfo.cs ├── PropertyMap.cs ├── RelationshipMap.cs ├── SqlBuilder.cs ├── SqlBuilderTask.cs ├── StatementsCreator.cs ├── ValuesObject.cs └── project.json └── README.md /.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 | [Rr]eleases/ 14 | x64/ 15 | x86/ 16 | build/ 17 | bld/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Roslyn cache directories 22 | *.ide/ 23 | 24 | # MSTest test Results 25 | [Tt]est[Rr]esult*/ 26 | [Bb]uild[Ll]og.* 27 | 28 | #NUNIT 29 | *.VisualState.xml 30 | TestResult.xml 31 | 32 | # Build Results of an ATL Project 33 | [Dd]ebugPS/ 34 | [Rr]eleasePS/ 35 | dlldata.c 36 | 37 | *_i.c 38 | *_p.c 39 | *_i.h 40 | *.ilk 41 | *.meta 42 | *.obj 43 | *.pch 44 | *.pdb 45 | *.pgc 46 | *.pgd 47 | *.rsp 48 | *.sbr 49 | *.tlb 50 | *.tli 51 | *.tlh 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | *.vspscc 56 | *.vssscc 57 | .builds 58 | *.pidb 59 | *.svclog 60 | *.scc 61 | 62 | # Chutzpah Test files 63 | _Chutzpah* 64 | 65 | # Visual C++ cache files 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opensdf 70 | *.sdf 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # TFS 2012 Local Workspace 79 | $tf/ 80 | 81 | # Guidance Automation Toolkit 82 | *.gpState 83 | 84 | # ReSharper is a .NET coding add-in 85 | _ReSharper*/ 86 | *.[Rr]e[Ss]harper 87 | *.DotSettings.user 88 | 89 | # JustCode is a .NET coding addin-in 90 | .JustCode 91 | 92 | # TeamCity is a build add-in 93 | _TeamCity* 94 | 95 | # DotCover is a Code Coverage Tool 96 | *.dotCover 97 | 98 | # NCrunch 99 | _NCrunch_* 100 | .*crunch*.local.xml 101 | 102 | # MightyMoose 103 | *.mm.* 104 | AutoTest.Net/ 105 | 106 | # Web workbench (sass) 107 | .sass-cache/ 108 | 109 | # Installshield output folder 110 | [Ee]xpress/ 111 | 112 | # DocProject is a documentation generator add-in 113 | DocProject/buildhelp/ 114 | DocProject/Help/*.HxT 115 | DocProject/Help/*.HxC 116 | DocProject/Help/*.hhc 117 | DocProject/Help/*.hhk 118 | DocProject/Help/*.hhp 119 | DocProject/Help/Html2 120 | DocProject/Help/html 121 | 122 | # Click-Once directory 123 | publish/ 124 | 125 | # Publish Web Output 126 | *.[Pp]ublish.xml 127 | *.azurePubxml 128 | # TODO: Comment the next line if you want to checkin your web deploy settings 129 | # but database connection strings (with potential passwords) will be unencrypted 130 | *.pubxml 131 | *.publishproj 132 | 133 | # NuGet Packages 134 | *.nupkg 135 | # The packages folder can be ignored because of Package Restore 136 | **/packages/* 137 | # except build/, which is used as an MSBuild target. 138 | !**/packages/build/ 139 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 140 | #!**/packages/repositories.config 141 | 142 | # Windows Azure Build Output 143 | csx/ 144 | *.build.csdef 145 | 146 | # Windows Store app package directory 147 | AppPackages/ 148 | 149 | # Others 150 | sql/ 151 | *.Cache 152 | ClientBin/ 153 | [Ss]tyle[Cc]op.* 154 | ~$* 155 | *~ 156 | *.dbmdl 157 | *.dbproj.schemaview 158 | *.pfx 159 | *.publishsettings 160 | node_modules/ 161 | 162 | # RIA/Silverlight projects 163 | Generated_Code/ 164 | 165 | # Backup & report files from converting an old project file 166 | # to a newer Visual Studio version. Backup files are not needed, 167 | # because we have git ;-) 168 | _UpgradeReport_Files/ 169 | Backup*/ 170 | UpgradeLog*.XML 171 | UpgradeLog*.htm 172 | 173 | # SQL Server files 174 | *.mdf 175 | *.ldf 176 | 177 | # Business Intelligence projects 178 | *.rdl.data 179 | *.bim.layout 180 | *.bim_*.settings 181 | 182 | # Microsoft Fakes 183 | FakesAssemblies/ 184 | -------------------------------------------------------------------------------- /.vs/Poco.Sql.NetCore/v15/sqlite3/storage.ide: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developer82/Poco.Sql.NetCore/e48b2012ccb1fac6867ddf1c0dff3a0ea2f41a73/.vs/Poco.Sql.NetCore/v15/sqlite3/storage.ide -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ophir Oren 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 | -------------------------------------------------------------------------------- /Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developer82/Poco.Sql.NetCore/e48b2012ccb1fac6867ddf1c0dff3a0ea2f41a73/Logo.png -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Demo/Poco.Sql.NetCore.Demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.0 5 | Poco.Sql.NetCore.Demo 6 | Exe 7 | Poco.Sql.NetCore.Demo 8 | $(PackageTargetFallback);dnxcore50 9 | false 10 | false 11 | false 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Demo/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using Poco.Sql.NetCore.Exceptions; 5 | using Poco.Sql.NetCore.Test.Models; 6 | using Poco.Sql.NetCore.Test.Models.Mappings; 7 | using Poco.Sql.NetCore.UnitTests; 8 | using UnitTestRunner; 9 | 10 | namespace Poco.Sql.NetCore.Demo 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | // TODO: Bug: Values are injected in WHERE statement when they should be parameterized 17 | 18 | Console.ForegroundColor = ConsoleColor.DarkGreen; 19 | Console.WriteLine(@" ____ __ ___ __ ____ __ __ "); 20 | Console.WriteLine(@"( _ \ / \ / __)/ \ / ___) / \ ( ) "); 21 | Console.WriteLine(@" ) __/( O )( (__( O )_ \___ \( O )/ (_/\"); 22 | Console.WriteLine(@"(__) \__/ \___)\__/(_)(____/ \__\)\____/"); 23 | Console.WriteLine(""); 24 | Console.WriteLine("Poco.Sql"); 25 | Console.WriteLine("Written by Ophir Oren. All rights reserved © Ophir Oren 2015-2018."); 26 | Console.WriteLine("Released under MIT license."); 27 | Console.WriteLine("http://www.webe.co.il"); 28 | Console.WriteLine(""); 29 | Console.ResetColor(); 30 | 31 | TestRunner testRunner = new TestRunner(); 32 | testRunner.RunTestClass(typeof(PocoSqlTests)); 33 | 34 | // PocoSql configuration 35 | Configuration.Initialize(config => 36 | { 37 | config.PluralizeTableNames(); 38 | config.SetStoreProcedurePrefix("stp_"); 39 | //config.ShowComments(); 40 | //config.InjectValuesInQueies(); 41 | //config.SelectFullGraph(); // TODO: not completed yet 42 | 43 | config.AddMap(new UserMap()); 44 | config.AddMap(new OrderMap()); 45 | config.AddMap(new VUserMap()); 46 | }); 47 | 48 | var user = Helper.GetUser(); 49 | var vUser = Helper.GetVUser(); 50 | 51 | Stopwatch swStopwatch = new Stopwatch(); 52 | swStopwatch.Start(); 53 | var currentlyTestingSql = user.PocoSql().Select().Where(u => u.Name.Equals("ophir")).ToString(); 54 | swStopwatch.Stop(); 55 | 56 | // Currently testing 57 | Console.WriteLine( 58 | Environment.NewLine + 59 | Environment.NewLine + "~~~~~~~~~~~~~~~~~~~~~~~~~" + Environment.NewLine + "Currently developing: " + Environment.NewLine + currentlyTestingSql); 60 | Console.WriteLine("Time elapsed: {0}", swStopwatch.Elapsed); 61 | 62 | Console.ReadLine(); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Demo/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: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("Poco.Sql.NetCore.Demo")] 11 | [assembly: AssemblyTrademark("")] 12 | 13 | // Setting ComVisible to false makes the types in this assembly not visible 14 | // to COM components. If you need to access a type in this assembly from 15 | // COM, set the ComVisible attribute to true on that type. 16 | [assembly: ComVisible(false)] 17 | 18 | // The following GUID is for the ID of the typelib if this project is exposed to COM 19 | [assembly: Guid("92de23aa-482e-437e-ab33-0b475321e95f")] 20 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/Helper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Poco.Sql.NetCore.Test.Models 6 | { 7 | public class Helper 8 | { 9 | public static User GetUser() 10 | { 11 | return new User() 12 | { 13 | UserId = 1, 14 | Age = 32, 15 | Name = "Ophir", 16 | Birthday = new DateTime(1982, 5, 6) 17 | }; 18 | } 19 | 20 | public static VUser GetVUser() 21 | { 22 | return new VUser() 23 | { 24 | UserId = 1, 25 | Age = 32, 26 | Name = "Ophir", 27 | Birthday = new DateTime(1982, 5, 6) 28 | }; 29 | } 30 | 31 | public static List GetListOfOrders() 32 | { 33 | var user = GetUser(); 34 | 35 | return new List() 36 | { 37 | new Order() { UserId = 1, User = user, ItemName = "Item 1", OrderId = 1, Quantity = 5 }, 38 | new Order() { UserId = 1, User = user, ItemName = "Item 2", OrderId = 1, Quantity = 4 }, 39 | new Order() { UserId = 1, User = user, ItemName = "Item 3", OrderId = 1, Quantity = 3 }, 40 | new Order() { UserId = 1, User = user, ItemName = "Item 4", OrderId = 1, Quantity = 2 }, 41 | new Order() { UserId = 1, User = user, ItemName = "Item 5", OrderId = 1, Quantity = 1 } 42 | }; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/Mappings/OrderMap.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore.Test.Models.Mappings 2 | { 3 | public class OrderMap : PocoSqlMapping 4 | { 5 | public OrderMap() 6 | { 7 | // Primary Key 8 | this.HasKey(t => t.OrderId); 9 | 10 | // Table & Column Mappings 11 | this.ToTable("Orders"); 12 | 13 | this.HasOptional(t => t.User) 14 | .WithMany(t => t.Orders) 15 | .HasForeignKey(d => d.UserId); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/Mappings/UserMap.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore.Test.Models.Mappings 2 | { 3 | public class UserMap : PocoSqlMapping 4 | { 5 | public UserMap() 6 | { 7 | // Primary Key 8 | this.HasKey(t => t.UserId).AutoGenerated(); 9 | 10 | // Properties 11 | this.Property(t => t.Name) 12 | .IsRequired() 13 | .HasMaxLength(20); 14 | 15 | // Table & Column Mappings 16 | this.ToTable("Users"); 17 | this.Property(t => t.Name).HasColumnName("Name"); 18 | this.Property(t => t.Birthday).HasColumnName("DateOfBirth"); 19 | this.Property(t => t.Age).Ignore(); 20 | 21 | /* 22 | this.MapToStoredProcedures(s => 23 | { 24 | s.Update().IncludeExecution().IncludeParameters(); //TODO: BUG - why does the result includes where caluse??? ---> exec stp_User_UpdateAge = @Age, Name = @Name, Birthday = @Birthday where UserId= 1; 25 | }); 26 | */ 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/Mappings/VUserMap.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore.Test.Models.Mappings 2 | { 3 | public class VUserMap : PocoSqlMapping 4 | { 5 | public VUserMap() 6 | { 7 | // Primary Key 8 | this.HasKey(t => t.UserId); 9 | 10 | this.IsVirtual(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/Order.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore.Test.Models 2 | { 3 | public class Order 4 | { 5 | public int OrderId { get; set; } 6 | public int UserId { get; set; } 7 | public string ItemName { get; set; } 8 | public int Quantity { get; set; } 9 | public User User { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/Poco.Sql.NetCore.Test.Models.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | Poco.Sql.NetCore.Test.Models 6 | Poco.Sql.NetCore.Test.Models 7 | $(PackageTargetFallback);dnxcore50 8 | false 9 | false 10 | false 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/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: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("Poco.Sql.NetCore.Test.Models")] 11 | [assembly: AssemblyTrademark("")] 12 | 13 | // Setting ComVisible to false makes the types in this assembly not visible 14 | // to COM components. If you need to access a type in this assembly from 15 | // COM, set the ComVisible attribute to true on that type. 16 | [assembly: ComVisible(false)] 17 | 18 | // The following GUID is for the ID of the typelib if this project is exposed to COM 19 | [assembly: Guid("8f7297f4-4944-4262-9cdc-5831374172d7")] 20 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/SuperUser.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore.Test.Models 2 | { 3 | public class SuperUser : User 4 | { 5 | public string Username { get; set; } 6 | public string Password { get; set; } 7 | public int Permissions { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Poco.Sql.NetCore.Test.Models 5 | { 6 | public class User 7 | { 8 | public User() 9 | { 10 | Orders = new List(); 11 | } 12 | 13 | public int UserId { get; set; } 14 | public int Age { get; set; } 15 | public string Name { get; set; } 16 | public DateTime Birthday { get; set; } 17 | public IList Orders { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.Test.Models/VUser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Poco.Sql.NetCore.Test.Models 5 | { 6 | public class VUser 7 | { 8 | public VUser() 9 | { 10 | Orders = new List(); 11 | } 12 | 13 | public int UserId { get; set; } 14 | public int Age { get; set; } 15 | public string Name { get; set; } 16 | public DateTime Birthday { get; set; } 17 | public IList Orders { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.UnitTests/Poco.Sql.NetCore.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.UnitTests/PocoSqlTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection.Metadata; 3 | using FluentAssertions; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Poco.Sql.NetCore.Test.Models; 6 | using Poco.Sql.NetCore.Test.Models.Mappings; 7 | 8 | namespace Poco.Sql.NetCore.UnitTests 9 | { 10 | [TestClass] 11 | public class PocoSqlTests 12 | { 13 | private User _user; 14 | private VUser _vUser; 15 | 16 | public PocoSqlTests() 17 | { 18 | Configuration.Initialize(config => 19 | { 20 | config.PluralizeTableNames(); 21 | config.SetStoreProcedurePrefix("stp_"); 22 | //config.ShowComments(); 23 | //config.InjectValuesInQueies(); 24 | //config.SelectFullGraph(); // TODO: not completed yet 25 | 26 | config.AddMap(new UserMap()); 27 | config.AddMap(new OrderMap()); 28 | config.AddMap(new VUserMap()); 29 | }); 30 | 31 | _user = Helper.GetUser(); 32 | _vUser = Helper.GetVUser(); 33 | } 34 | 35 | [TestMethod] 36 | public void Generate_Select_Query_From_Object() 37 | { 38 | string sql = _user.PocoSql().Select().ToString(); 39 | sql.Should().Be("select UserId, Age, Name, DateOfBirth as Birthday from Users;"); 40 | } 41 | 42 | [TestMethod] 43 | public void Generate_Insert_Statement_From_Object() 44 | { 45 | var sql = _user.PocoSql().Insert().ToString(); 46 | sql.Should().Be("insert into Users (Age, Name, Birthday) values(@Age, @Name, @Birthday);"); 47 | } 48 | 49 | [TestMethod] 50 | public void Generate_Update_Statement_From_Object() 51 | { 52 | var sql = _user.PocoSql().Update().ToString(); 53 | sql.Should().Be("update Users set Age = @Age, Name = @Name, Birthday = @Birthday where (UserId = @UserId);"); 54 | } 55 | 56 | [TestMethod] 57 | public void Generate_Delete_Statement_From_Object() 58 | { 59 | var sql = _user.PocoSql().Delete().ToString(); 60 | sql.Should().Be("delete from Users where (UserId = @UserId);"); 61 | } 62 | 63 | [TestMethod] 64 | public void Generate_Select_Query_From_Object_With_Virtual_Mapping() 65 | { 66 | var sql = _vUser.PocoSql().Select().ToString(); 67 | sql.Should().Be("select UserId, Age, Name, Birthday from VUser;"); 68 | } 69 | 70 | [TestMethod] 71 | public void Generate_Select_Query_With_Where_From_Object_With_Virtual_Mapping() 72 | { 73 | var sql = _vUser.PocoSql().Select().Where(u => u.UserId == 1).ToString(); 74 | sql.Should().Be("select UserId, Age, Name, Birthday from VUser where ((UserId = @UserId));"); 75 | } 76 | 77 | [TestMethod] 78 | public void Generate_Select_Query_With_DateTime_Where_From_Object_With_Virtual_Mapping() 79 | { 80 | DateTime fiftyYears = DateTime.Now.AddYears(-50); 81 | DateTime now = DateTime.Now; 82 | var sql = _vUser.PocoSql().Select().Where(u => u.Birthday > fiftyYears && u.Birthday < now).ToString(); // TODO: this query is not performing correctly 83 | sql.Should().Be($"select UserId, Age, Name, Birthday from VUser where(((Birthday > {fiftyYears}) and(Birthday < {now})));"); 84 | } 85 | 86 | [TestMethod] 87 | [ExpectedException(typeof(Exceptions.CantUpdateVirtualException))] 88 | public void Insert_Or_Update_Statements_On_Virtual_Mapping_Objects_Should_Throw_Exception() 89 | { 90 | var sql = _vUser.PocoSql().Insert().ToString(); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.UnitTests/UnitTestsRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Poco.Sql.NetCore.UnitTests 6 | { 7 | public class UnitTestsRunner 8 | { 9 | public bool RunTest(Action testMethod) 10 | { 11 | try 12 | { 13 | testMethod.Invoke(); 14 | return true; 15 | } 16 | catch (Exception e) 17 | { 18 | return false; 19 | } 20 | } 21 | 22 | public bool RunTest(Action testMethod, string testText, string passText, string failText) 23 | { 24 | if (RunTest(testMethod)) 25 | { 26 | 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Poco.Sql.NetCore.Demo", "Poco.Sql.NetCore.Demo\Poco.Sql.NetCore.Demo.csproj", "{92DE23AA-482E-437E-AB33-0B475321E95F}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Poco.Sql.NetCore.Test.Models", "Poco.Sql.NetCore.Test.Models\Poco.Sql.NetCore.Test.Models.csproj", "{8F7297F4-4944-4262-9CDC-5831374172D7}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Poco.Sql.NetCore", "Poco.Sql.NetCore\Poco.Sql.NetCore.csproj", "{A51E327A-41F0-46A6-8892-AEF5E40ECCD0}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Poco.Sql.NetCore.UnitTests", "Poco.Sql.NetCore.UnitTests\Poco.Sql.NetCore.UnitTests.csproj", "{6E86D7F1-4B91-4C4F-A1E9-09E49DF7C477}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {92DE23AA-482E-437E-AB33-0B475321E95F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {92DE23AA-482E-437E-AB33-0B475321E95F}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {92DE23AA-482E-437E-AB33-0B475321E95F}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {92DE23AA-482E-437E-AB33-0B475321E95F}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {8F7297F4-4944-4262-9CDC-5831374172D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {8F7297F4-4944-4262-9CDC-5831374172D7}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {8F7297F4-4944-4262-9CDC-5831374172D7}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {8F7297F4-4944-4262-9CDC-5831374172D7}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {A51E327A-41F0-46A6-8892-AEF5E40ECCD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {A51E327A-41F0-46A6-8892-AEF5E40ECCD0}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {A51E327A-41F0-46A6-8892-AEF5E40ECCD0}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {A51E327A-41F0-46A6-8892-AEF5E40ECCD0}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {6E86D7F1-4B91-4C4F-A1E9-09E49DF7C477}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {6E86D7F1-4B91-4C4F-A1E9-09E49DF7C477}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {6E86D7F1-4B91-4C4F-A1E9-09E49DF7C477}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {6E86D7F1-4B91-4C4F-A1E9-09E49DF7C477}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {EF3D776C-A417-4271-9CA0-14BB4D64C598} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Poco.Sql.NetCore.Interfaces; 4 | 5 | namespace Poco.Sql.NetCore 6 | { 7 | public class Configuration 8 | { 9 | private static Object _lock = new Object(); 10 | private static bool _initialized; 11 | private static Dictionary _mappings = new Dictionary(); 12 | 13 | internal static bool IsPluralizeTableNames { get; private set; } 14 | internal static bool FullGraphSelecttion { get; private set; } 15 | internal static bool ValuesInQueies { get; private set; } 16 | internal static bool CachingDisabled { get; private set; } 17 | internal static bool Comment { get; private set; } 18 | internal static string StoredProceduresPrefix { get; private set; } 19 | internal static Dictionary Mappings = new Dictionary(); 20 | 21 | public static void Initialize(Action config) 22 | { 23 | if (_initialized) return; 24 | 25 | lock (_lock) 26 | { 27 | if (_initialized) return; 28 | config.Invoke(new Configuration()); 29 | _initialized = true; 30 | } 31 | } 32 | 33 | public void PluralizeTableNames() 34 | { 35 | IsPluralizeTableNames = true; 36 | } 37 | 38 | public void SelectFullGraph() 39 | { 40 | FullGraphSelecttion = true; 41 | } 42 | 43 | public void InjectValuesInQueies() 44 | { 45 | ValuesInQueies = true; 46 | } 47 | 48 | public void DisableCache() 49 | { 50 | CachingDisabled = true; 51 | } 52 | 53 | public void ShowComments() 54 | { 55 | Comment = true; 56 | } 57 | 58 | public void SetStoreProcedurePrefix(string prefix) 59 | { 60 | StoredProceduresPrefix = prefix; 61 | } 62 | 63 | public void AddMap(PocoSqlMapping mapping) 64 | { 65 | _mappings.Add(typeof(T).FullName, mapping); 66 | } 67 | 68 | internal static bool HasMap(string key) 69 | { 70 | return _mappings.ContainsKey(key); 71 | } 72 | 73 | internal static IPocoSqlMapping GetMap(string key) 74 | { 75 | return (IPocoSqlMapping)_mappings[key]; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/Exceptions/CantUpdateVirtualException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Poco.Sql.NetCore.Exceptions 4 | { 5 | public class CantUpdateVirtualException : Exception 6 | { 7 | public override string Message 8 | { 9 | get 10 | { 11 | return "You are trying to create a SQL statement for virtual/view mapping object, which does not represet an actual table in the database"; 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/Exceptions/NoSqlBuilderTaskFound.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Poco.Sql.NetCore.Exceptions 4 | { 5 | public class NoSqlBuilderTaskFound : Exception 6 | { 7 | public override string Message 8 | { 9 | get 10 | { 11 | return "No tasks were found for sql build."; 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/Helpers/ExpressionEvaluator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace Poco.Sql.NetCore.Helpers 5 | { 6 | class ExpressionEvaluator 7 | { 8 | #region Eval 9 | internal static string Eval(object expression, bool injectValuesToQueies) 10 | { 11 | return Eval(expression, null, String.Empty, injectValuesToQueies); 12 | } 13 | 14 | internal static string Eval(object expression, object parentExpression, string statementStr, bool injectValuesToQueies) 15 | { 16 | if (expression is BinaryExpression) 17 | statementStr += processBinaryExpression((BinaryExpression)expression, injectValuesToQueies); 18 | else if (expression is MethodCallExpression) 19 | statementStr += processMethodCallExpression((MethodCallExpression)expression, (Expression)parentExpression, injectValuesToQueies); 20 | else if (expression is UnaryExpression) 21 | statementStr += processUnaryExpression((UnaryExpression)expression, (Expression)expression, injectValuesToQueies); 22 | else if (expression is MemberExpression) 23 | statementStr += processMemberExpression((MemberExpression)expression, parentExpression, injectValuesToQueies); 24 | else if (expression is ConstantExpression) 25 | statementStr += processConstantExpression((ConstantExpression)expression, parentExpression, injectValuesToQueies); 26 | 27 | return statementStr; 28 | } 29 | #endregion 30 | 31 | #region processBinaryExpression 32 | private static string processBinaryExpression(BinaryExpression binaryExpression, bool injectValuesToQueies) 33 | { 34 | string result; 35 | 36 | var leftExpression = binaryExpression.Left; 37 | var rightExpression = binaryExpression.Right; 38 | 39 | result = String.Format("({0}{1}{2})", 40 | Eval(leftExpression, binaryExpression, String.Empty, injectValuesToQueies), 41 | convertNodeTypeToStr(binaryExpression.NodeType), 42 | Eval(rightExpression, binaryExpression, String.Empty, injectValuesToQueies)); 43 | 44 | return result; 45 | } 46 | #endregion 47 | 48 | #region processMethodCallExpression 49 | private static string processMethodCallExpression(MethodCallExpression methodCallExpression, Expression parentExpression, bool injectValuesToQueies) 50 | { 51 | string result = String.Empty; 52 | string constantExpressionValue = String.Empty; 53 | 54 | if (methodCallExpression.Arguments.Count > 0) 55 | { 56 | if (methodCallExpression.Arguments[0] is ConstantExpression) 57 | constantExpressionValue = ((ConstantExpression) methodCallExpression.Arguments[0]).Value.ToString(); 58 | else if (methodCallExpression.Arguments[0] is MemberExpression) 59 | constantExpressionValue = processMemberExpression((MemberExpression) methodCallExpression.Arguments[0], 60 | parentExpression, injectValuesToQueies); 61 | } 62 | 63 | var expressionStr = methodCallExpression.Object.ToString(); 64 | expressionStr = expressionStr.Substring(expressionStr.LastIndexOf('.') + 1); 65 | 66 | var value = String.Empty; 67 | var valueWrapper = methodCallExpression.Object.Type == typeof(String) ? "'" : String.Empty; 68 | var entireExpStr = methodCallExpression.ToString(); 69 | 70 | if (entireExpStr.IndexOf(".Equals") > -1) 71 | { 72 | if (!injectValuesToQueies) 73 | { 74 | constantExpressionValue = "@" + expressionStr; 75 | valueWrapper = String.Empty; 76 | } 77 | 78 | result = String.Format("{0} = {1}{2}{1}", 79 | expressionStr, 80 | valueWrapper, 81 | constantExpressionValue); 82 | } 83 | else if (entireExpStr.IndexOf(".IndexOf") > -1) 84 | { 85 | BinaryExpression binaryParentExp = (BinaryExpression)parentExpression; 86 | int indexOfComparisonValue = Expression.Lambda>(binaryParentExp.Right).Compile().Invoke(); 87 | 88 | if (methodCallExpression.NodeType == ExpressionType.GreaterThan && indexOfComparisonValue == -1) 89 | { 90 | result = String.Format(" like '%{0}%'", constantExpressionValue); 91 | } 92 | } 93 | else 94 | { 95 | string expressionValue = getExpressionValue(methodCallExpression); 96 | if (String.IsNullOrEmpty(expressionValue)) 97 | result = expressionStr; 98 | else 99 | result = expressionValue; 100 | } 101 | 102 | return result; 103 | } 104 | #endregion 105 | 106 | #region processUnaryExpression 107 | private static string processUnaryExpression(UnaryExpression unaryExpression, Expression parentExpression, bool injectValuesToQueies) 108 | { 109 | string result = String.Empty; 110 | 111 | if (unaryExpression.NodeType == ExpressionType.Not || unaryExpression.NodeType == ExpressionType.NotEqual) 112 | result = "not "; 113 | 114 | result += Eval(unaryExpression.Operand, parentExpression, String.Empty, injectValuesToQueies); 115 | return result; 116 | } 117 | #endregion 118 | 119 | #region processMemberExpression 120 | private static string processMemberExpression(MemberExpression memberExpression, object parentExpression, bool injectValuesToQueies) 121 | { 122 | string result = String.Empty; 123 | if (memberExpression.Expression is ConstantExpression) 124 | { 125 | if (!injectValuesToQueies && parentExpression is BinaryExpression) 126 | return getParameterziedValue(memberExpression, (BinaryExpression)parentExpression); 127 | 128 | return getExpressionValue(memberExpression); 129 | } 130 | else 131 | { 132 | result = memberExpression.ToString(); 133 | result = result.Substring(result.LastIndexOf('.') + 1); 134 | } 135 | return result; 136 | } 137 | #endregion 138 | 139 | #region processConstantExpression 140 | private static string processConstantExpression(ConstantExpression expression, object parentExpression, bool injectValuesToQueies) 141 | { 142 | if (!injectValuesToQueies && parentExpression is BinaryExpression) 143 | return getParameterziedValue(expression, (BinaryExpression)parentExpression); 144 | 145 | return expression.ToString(); 146 | } 147 | #endregion 148 | 149 | #region getExpressionValue 150 | private static string getExpressionValue(Expression expression) 151 | { 152 | try 153 | { 154 | Expression conversion = Expression.Convert(expression, typeof(object)); 155 | Func func = Expression.Lambda>(conversion).Compile(); 156 | 157 | object value = func.Invoke(); 158 | if (value == null) 159 | return string.Empty; 160 | 161 | return value.ToString(); 162 | } 163 | catch (Exception ex) 164 | { 165 | return String.Empty; 166 | } 167 | } 168 | #endregion 169 | 170 | #region getParameterziedValue 171 | private static string getParameterziedValue(Expression originalExpression, BinaryExpression parentExpression) 172 | { 173 | string fieldName; 174 | if (parentExpression.Left == originalExpression) 175 | fieldName = Eval(parentExpression.Right, false); 176 | else 177 | fieldName = Eval(parentExpression.Left, false); 178 | 179 | return "@" + fieldName; 180 | } 181 | #endregion 182 | 183 | #region convertNodeTypeToStr 184 | private static string convertNodeTypeToStr(ExpressionType nodeType) 185 | { 186 | string result; 187 | switch (nodeType) 188 | { 189 | case ExpressionType.Equal: 190 | result = " = "; 191 | break; 192 | case ExpressionType.Not: 193 | case ExpressionType.NotEqual: 194 | result = " not "; 195 | break; 196 | case ExpressionType.GreaterThan: 197 | result = " > "; 198 | break; 199 | case ExpressionType.GreaterThanOrEqual: 200 | result = " >= "; 201 | break; 202 | case ExpressionType.LessThan: 203 | result = " < "; 204 | break; 205 | case ExpressionType.LessThanOrEqual: 206 | result = " <= "; 207 | break; 208 | case ExpressionType.AndAlso: 209 | case ExpressionType.And: 210 | result = " and "; 211 | break; 212 | case ExpressionType.OrElse: 213 | case ExpressionType.Or: 214 | result = " or "; 215 | break; 216 | default: 217 | result = String.Empty; 218 | break; 219 | } 220 | 221 | return result; 222 | } 223 | #endregion 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/Interfaces/IPocoSqlMapping.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore.Interfaces 2 | { 3 | public interface IPocoSqlMapping 4 | { 5 | string GetTableName(); 6 | string GetPrimaryKey(); 7 | string GetQueryByName(string name); 8 | PocoSqlStoredProceduresMapping GetStoredProceduresMappings(); 9 | PocoSqlCostomMapping GetCustomMappings(); 10 | bool GetPrimaryAutoGenerated(); 11 | bool GetIsVirtual(); 12 | PropertyMap GetMapping(string propertyName); 13 | IRelationshipMap GetRelationship(string propertyName); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/Interfaces/IRelationshipMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Poco.Sql.NetCore.Interfaces 4 | { 5 | public interface IRelationshipMap 6 | { 7 | string GetForeignKey(); 8 | Type GetRelatedObjectType(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/Poco.Sql.NetCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Lightweight .NET Core library for generating SQL statements from plain objects with advanced features and mapping support 5 | Copyright (c) 2016 Ophir Oren 6 | Poco.Sql.NetCore 7 | Ophir Oren 8 | netstandard2.0 9 | true 10 | Poco.Sql.NetCore 11 | Poco.Sql.NetCore 12 | ORM;DAL;ado.net;data;recordset;sql;query;generator;batch;database;micro-orm;data-mapper;poco;schema-less;netstandard;netcore;net45 13 | https://github.com/developer82/Poco.Sql.NetCore/blob/master/Logo.png 14 | https://github.com/developer82/Poco.Sql.NetCore 15 | https://github.com/developer82/Poco.Sql.NetCore/blob/master/LICENSE 16 | false 17 | false 18 | false 19 | True 20 | 2.0.1 21 | 2.0.1 22 | ----- 23 | Added useful extension methods for more fluent work. 24 | 25 | 2.0.0 26 | ----- 27 | Update to .NET Standard 2.0. 28 | Library version also updated to 2.0.0 to be consisted with the new 2.0. 29 | For erlier .NET Core or .NET Standard versions, use version < 2.0.0 30 | 31 | 1.0.1 32 | ----- 33 | - Minor bug fixes 34 | - New Poco extensions that support generic typings 35 | 2.0.0.1 36 | 2.0.0.1 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/PocoSqlCostomMapping.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore 2 | { 3 | public class PocoSqlCostomMapping 4 | { 5 | public string SelectQuery { get; private set; } 6 | public string InsertQuery { get; private set; } 7 | public string UpdateQuery { get; private set; } 8 | public string DeleteQuery { get; private set; } 9 | 10 | public void Select(string sqlStatement) 11 | { 12 | SelectQuery = sqlStatement; 13 | } 14 | 15 | public void Insert(string sqlStatement) 16 | { 17 | InsertQuery = sqlStatement; 18 | } 19 | 20 | public void Update(string sqlStatement) 21 | { 22 | UpdateQuery = sqlStatement; 23 | } 24 | 25 | public void Delete(string sqlStatement) 26 | { 27 | DeleteQuery = sqlStatement; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/PocoSqlExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Poco.Sql.NetCore 4 | { 5 | public static class PocoSqlExtensions 6 | { 7 | public static SqlBuilder PocoSql(this Object obj) 8 | { 9 | return new SqlBuilder(obj); 10 | } 11 | 12 | public static SqlBuilder PocoSql() 13 | { 14 | var obj = (object)Activator.CreateInstance(); 15 | return new SqlBuilder(obj); 16 | } 17 | 18 | public static SqlBuilder PocoSql(this Object obj) 19 | { 20 | var pocoObj = (object)Activator.CreateInstance(); 21 | return new SqlBuilder(pocoObj); 22 | } 23 | 24 | public static SqlBuilder SqlBuilder(this Object obj) 25 | { 26 | return new SqlBuilder(obj); 27 | } 28 | 29 | public static SqlBuilder SqlBuilder() 30 | { 31 | var obj = (object)Activator.CreateInstance(); 32 | return new SqlBuilder(obj); 33 | } 34 | 35 | public static SqlBuilder SqlBuilder(this Object obj) 36 | { 37 | var pocoObj = (object)Activator.CreateInstance(); 38 | return new SqlBuilder(pocoObj); 39 | } 40 | 41 | public static SqlBuilder Select(this Object obj) 42 | { 43 | return (new SqlBuilder(obj)).Select(); 44 | } 45 | 46 | public static SqlBuilder Insert(this Object obj) 47 | { 48 | return (new SqlBuilder(obj)).Insert(); 49 | } 50 | 51 | public static SqlBuilder Update(this Object obj) 52 | { 53 | return (new SqlBuilder(obj)).Update(); 54 | } 55 | 56 | public static SqlBuilder Delete(this Object obj) 57 | { 58 | return (new SqlBuilder(obj)).Delete(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/PocoSqlMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using Poco.Sql.NetCore.Interfaces; 5 | 6 | namespace Poco.Sql.NetCore 7 | { 8 | public class PocoSqlMapping : IPocoSqlMapping 9 | { 10 | public string SchemeName { get; private set; } 11 | public string TableName { get; private set; } 12 | public string PrimaryKey { get; private set; } 13 | public bool PrimaryKeyAutoGenerated { get; private set; } 14 | public bool Virtual { get; private set; } 15 | 16 | private Dictionary _namedQueries; 17 | private Dictionary _mappedProperties; 18 | private Dictionary _mappedRelationships; 19 | private PocoSqlStoredProceduresMapping _mappedStoredProcedures; 20 | private PocoSqlCostomMapping _mappedCustomQueries; 21 | 22 | public PocoSqlMapping() 23 | { 24 | _mappedProperties = new Dictionary(); 25 | _mappedRelationships = new Dictionary(); 26 | _namedQueries = new Dictionary(); 27 | TableName = typeof(T).Name; 28 | } 29 | 30 | public string GetTableName() 31 | { 32 | return (String.IsNullOrEmpty(SchemeName) ? String.Empty : SchemeName + ".") + TableName; 33 | } 34 | 35 | public PocoSqlMapping HasKey(Expression> keyExpression) 36 | { 37 | PrimaryKey = ((MemberExpression)keyExpression.Body).Member.Name; 38 | return this; 39 | } 40 | 41 | public PocoSqlMapping AutoGenerated() 42 | { 43 | PrimaryKeyAutoGenerated = true; 44 | return this; 45 | } 46 | 47 | public PocoSqlMapping ToTable(string tableName) 48 | { 49 | return ToTable(tableName, String.Empty); 50 | } 51 | 52 | public PocoSqlMapping ToTable(string tableName, string schemeName) 53 | { 54 | SchemeName = schemeName; 55 | TableName = tableName; 56 | return this; 57 | } 58 | 59 | public PocoSqlMapping IsView() 60 | { 61 | return IsVirtual(); 62 | } 63 | 64 | public PocoSqlMapping IsVirtual() 65 | { 66 | Virtual = true; 67 | return this; 68 | } 69 | 70 | public PocoSqlMapping MapToCustomQueries(Action customMappings) 71 | { 72 | _mappedCustomQueries = new PocoSqlCostomMapping(); 73 | customMappings.Invoke(_mappedCustomQueries); 74 | return this; 75 | } 76 | 77 | public PocoSqlMapping MapToStoredProcedures(Action storedProceduresMappings) 78 | { 79 | _mappedStoredProcedures = new PocoSqlStoredProceduresMapping(); 80 | storedProceduresMappings.Invoke(_mappedStoredProcedures); 81 | return this; 82 | } 83 | 84 | public PropertyMap Property(Expression> propertyExpression) 85 | { 86 | string propertyName = ((MemberExpression)propertyExpression.Body).Member.Name; 87 | 88 | PropertyMap propertyMap = null; 89 | if (_mappedProperties.ContainsKey(propertyName)) 90 | propertyMap = _mappedProperties[propertyName]; 91 | else 92 | propertyMap = new PropertyMap(propertyName); 93 | 94 | AddMapping(propertyName, propertyMap); 95 | 96 | return propertyMap; 97 | } 98 | 99 | public void AddMapping(string propertyName, PropertyMap map) 100 | { 101 | if (_mappedProperties.ContainsKey(propertyName)) 102 | _mappedProperties[propertyName] = map; 103 | else 104 | _mappedProperties.Add(propertyName, map); 105 | } 106 | 107 | public PropertyMap GetMapping(string propertyName) 108 | { 109 | PropertyMap propertyMap = null; 110 | if (_mappedProperties.ContainsKey(propertyName)) 111 | propertyMap = _mappedProperties[propertyName]; 112 | 113 | return propertyMap; 114 | } 115 | 116 | public RelationshipMap HasOptional(Expression> navigationPropertyExpression) 117 | { 118 | var relationshipMap = new RelationshipMap(); 119 | var navigationObjType = navigationPropertyExpression.Body.Type.ToString(); 120 | 121 | relationshipMap.RelatedObject = navigationPropertyExpression.Body.Type; 122 | _mappedRelationships.Add(navigationObjType, relationshipMap); 123 | 124 | return relationshipMap; 125 | } 126 | 127 | public PocoSqlMapping AddNamedQuery(string name, string sql) 128 | { 129 | _namedQueries.Add(name, sql); 130 | return this; 131 | } 132 | 133 | public string GetQueryByName(string name) 134 | { 135 | return _namedQueries[name]; 136 | } 137 | 138 | public IRelationshipMap GetRelationship(string propertyName) 139 | { 140 | return (IRelationshipMap)_mappedRelationships[propertyName]; 141 | } 142 | 143 | public string GetPrimaryKey() 144 | { 145 | return PrimaryKey; 146 | } 147 | 148 | public bool GetPrimaryAutoGenerated() 149 | { 150 | return PrimaryKeyAutoGenerated; 151 | } 152 | 153 | public PocoSqlStoredProceduresMapping GetStoredProceduresMappings() 154 | { 155 | return _mappedStoredProcedures; 156 | } 157 | 158 | public PocoSqlCostomMapping GetCustomMappings() 159 | { 160 | return _mappedCustomQueries; 161 | } 162 | 163 | public bool GetIsVirtual() 164 | { 165 | return Virtual; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/PocoSqlStoredProcedureMap.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore 2 | { 3 | public class PocoSqlStoredProcedureMap 4 | { 5 | public string Name { get; private set; } // The name of the stored procedure 6 | public bool Parameters { get; private set; } // By default the generated sql statement will not include the object parameters when mapped to stored procedure (most micro-orm frameworks does that and only require SP name) 7 | public bool Execution { get; private set; } // By default the generated sql statement will not include the 'exec' command (most micro-orm frameworks does that and only require SP name) 8 | 9 | public PocoSqlStoredProcedureMap HasName(string spName) 10 | { 11 | Name = spName; 12 | return this; 13 | } 14 | 15 | public PocoSqlStoredProcedureMap IncludeParameters() 16 | { 17 | Parameters = true; 18 | return this; 19 | } 20 | 21 | public PocoSqlStoredProcedureMap IncludeExecution() 22 | { 23 | Execution = true; 24 | return this; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/PocoSqlStoredProcedureMapping.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore 2 | { 3 | public class PocoSqlStoredProcedureMapping 4 | { 5 | public string SelectQuery { get; private set; } 6 | public string InsertQuery { get; private set; } 7 | public string UpdateQuery { get; private set; } 8 | public string DeleteQuery { get; private set; } 9 | 10 | public void Select(string spName) 11 | { 12 | SelectQuery = spName; 13 | } 14 | 15 | public void Insert(string spName) 16 | { 17 | InsertQuery = spName; 18 | } 19 | 20 | public void Update(string spName) 21 | { 22 | UpdateQuery = spName; 23 | } 24 | 25 | public void Delete(string spName) 26 | { 27 | DeleteQuery = spName; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/PocoSqlStoredProceduresMapping.cs: -------------------------------------------------------------------------------- 1 | namespace Poco.Sql.NetCore 2 | { 3 | public class PocoSqlStoredProceduresMapping 4 | { 5 | internal PocoSqlStoredProcedureMap SelectMap { get; private set; } 6 | internal PocoSqlStoredProcedureMap InsertMap { get; private set; } 7 | internal PocoSqlStoredProcedureMap UpdateMap { get; private set; } 8 | internal PocoSqlStoredProcedureMap DeleteMap { get; private set; } 9 | 10 | public PocoSqlStoredProcedureMap Select() 11 | { 12 | SelectMap = new PocoSqlStoredProcedureMap(); 13 | return SelectMap; 14 | } 15 | 16 | public PocoSqlStoredProcedureMap Insert() 17 | { 18 | InsertMap = new PocoSqlStoredProcedureMap(); 19 | return InsertMap; 20 | } 21 | 22 | public PocoSqlStoredProcedureMap Update() 23 | { 24 | UpdateMap = new PocoSqlStoredProcedureMap(); 25 | return UpdateMap; 26 | } 27 | 28 | public PocoSqlStoredProcedureMap Delete() 29 | { 30 | DeleteMap = new PocoSqlStoredProcedureMap(); 31 | return DeleteMap; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/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: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("Poco.Sql.NetCore")] 11 | [assembly: AssemblyTrademark("")] 12 | 13 | // Setting ComVisible to false makes the types in this assembly not visible 14 | // to COM components. If you need to access a type in this assembly from 15 | // COM, set the ComVisible attribute to true on that type. 16 | [assembly: ComVisible(false)] 17 | 18 | // The following GUID is for the ID of the typelib if this project is exposed to COM 19 | [assembly: Guid("47c16a4d-377d-40da-898a-5f3a014f249b")] 20 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/PropertyMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Poco.Sql.NetCore 4 | { 5 | public class PropertyMap 6 | { 7 | public string PropertyName { get; private set; } 8 | public string ColumnName { get; private set; } 9 | public bool Required { get; private set; } 10 | public bool Ignored { get; private set; } 11 | public int MaxLength { get; private set; } 12 | public Type FieldType { get; private set; } 13 | 14 | public PropertyMap(string propertyName) 15 | { 16 | PropertyName = propertyName; 17 | ColumnName = propertyName; 18 | } 19 | 20 | public PropertyMap HasColumnName(string columnName) 21 | { 22 | ColumnName = columnName; 23 | return this; 24 | } 25 | 26 | public PropertyMap Ignore() 27 | { 28 | Ignored = true; 29 | return this; 30 | } 31 | 32 | public PropertyMap IsRequired() //TODO: validate this property when building the query 33 | { 34 | return IsRequired(true); 35 | } 36 | 37 | public PropertyMap IsRequired(bool required) 38 | { 39 | Required = required; 40 | return this; 41 | } 42 | 43 | public PropertyMap HasMaxLength(int maxLength) //TODO: validate this property when building the query 44 | { 45 | MaxLength = maxLength; 46 | return this; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/RelationshipMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using Poco.Sql.NetCore.Interfaces; 5 | 6 | namespace Poco.Sql.NetCore 7 | { 8 | public class RelationshipMap : IRelationshipMap 9 | { 10 | private string _currentObject; 11 | private string _foreignKey; 12 | public Type RelatedObject { get; set; } 13 | 14 | public RelationshipMap WithMany(Expression>> navigationPropertyExpression) 15 | { 16 | _currentObject = navigationPropertyExpression.Body.ToString(); 17 | _currentObject = _currentObject.Substring(_currentObject.LastIndexOf('.') + 1); 18 | return this; 19 | } 20 | 21 | public RelationshipMap HasForeignKey(Expression> foreignKeyExpression) 22 | { 23 | _foreignKey = foreignKeyExpression.Body.ToString(); 24 | _foreignKey = _foreignKey.Substring(_foreignKey.LastIndexOf('.') + 1); 25 | return this; 26 | } 27 | 28 | 29 | public string GetForeignKey() 30 | { 31 | return _foreignKey; 32 | } 33 | 34 | 35 | public Type GetRelatedObjectType() 36 | { 37 | return RelatedObject; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/SqlBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | using System.Text; 7 | using Humanizer; 8 | using Poco.Sql.NetCore.Exceptions; 9 | using Poco.Sql.NetCore.Helpers; 10 | using Poco.Sql.NetCore.Interfaces; 11 | 12 | namespace Poco.Sql.NetCore 13 | { 14 | /// 15 | /// This class is responsible for building the SQL statements 16 | /// 17 | public class SqlBuilder 18 | { 19 | private static Dictionary _cachedQueries = new Dictionary(); //TODO: implement caching 20 | 21 | private List _tasks; 22 | 23 | private object _obj; 24 | 25 | private SqlBuilderTask currentTask 26 | { 27 | get { return _tasks[_tasks.Count - 1]; } 28 | } 29 | 30 | public string Result 31 | { 32 | get 33 | { 34 | return getSqlStatement(); 35 | } 36 | } 37 | 38 | public SqlBuilder(object obj) 39 | { 40 | _obj = obj; 41 | _tasks = new List(); 42 | } 43 | 44 | private void createTask(SqlBuilderTask task) 45 | { 46 | _tasks.Add(task); 47 | } 48 | 49 | private void createTask(SqlBuilderTask.QueryTypeEnum queryType) 50 | { 51 | var task = new SqlBuilderTask() 52 | { 53 | QueryType = queryType 54 | }; 55 | createTask(task); 56 | } 57 | 58 | public SqlBuilder NamedQuery(string name) 59 | { 60 | createTask(new SqlBuilderTask() 61 | { 62 | QueryType = SqlBuilderTask.QueryTypeEnum.QueryByName, 63 | QueryName = name 64 | }); 65 | 66 | //var map = getMapping(_obj); 67 | //if (map != null) 68 | // _sql = map.GetQueryByName(name); 69 | return this; 70 | } 71 | 72 | #region Select 73 | public SqlBuilder Select() 74 | { 75 | createTask(SqlBuilderTask.QueryTypeEnum.Select); 76 | return this; 77 | } 78 | 79 | public SqlBuilder Select(long id) 80 | { 81 | createTask(new SqlBuilderTask() 82 | { 83 | QueryType = SqlBuilderTask.QueryTypeEnum.Select, 84 | PrimaryKeyValue = id 85 | }); 86 | //createTask(SqlBuilderTask.QueryTypeEnum.Select, primaryKey + " = " + id); 87 | //string primaryKey = getPrimaryKey(_obj); 88 | //return buildSqlStatement(_obj, null, null, null, null).Where(primaryKey + " = " + id); 89 | return this; 90 | } 91 | 92 | public SqlBuilder Select(PocoSqlMapping map) 93 | { 94 | createTask(new SqlBuilderTask() 95 | { 96 | QueryType = SqlBuilderTask.QueryTypeEnum.Select, 97 | Map = map 98 | }); 99 | 100 | return this; 101 | } 102 | 103 | public SqlBuilder Select(string tableName) 104 | { 105 | createTask(new SqlBuilderTask() 106 | { 107 | QueryType = SqlBuilderTask.QueryTypeEnum.Select, 108 | TableName = tableName 109 | }); 110 | 111 | return this; 112 | } 113 | #endregion 114 | 115 | public SqlBuilder SelectScopeIdentity() 116 | { 117 | createTask(SqlBuilderTask.QueryTypeEnum.SelectScopeIdentity); 118 | return this; 119 | } 120 | 121 | public SqlBuilder SelectIdentity() 122 | { 123 | createTask(SqlBuilderTask.QueryTypeEnum.SelectIdentity); 124 | return this; 125 | } 126 | 127 | public SqlBuilder FullGraph() 128 | { 129 | throw new NotImplementedException(); 130 | 131 | //PropertyInfo[] propertyInfos = _obj.GetType().GetProperties(); 132 | 133 | //StringBuilder allFields = new StringBuilder(); 134 | //foreach (PropertyInfo propertyInfo in propertyInfos.Where(p => p.PropertyType.FullName.StartsWith("System.Collections"))) 135 | //{ 136 | // var collectionObject = propertyInfo.GetValue(_obj); 137 | // Type collectionType = collectionObject.GetType().GetGenericArguments()[0]; 138 | // object obj = Activator.CreateInstance(collectionType); 139 | 140 | // string key = obj.GetType().FullName; 141 | // if (Configuration.HasMap(key)) 142 | // { 143 | // var map = Configuration.GetMap(key);; 144 | // var relationship = map.GetRelationship(_obj.GetType().FullName); 145 | 146 | // string currentKey = _obj.GetType().FullName; 147 | // var currentMap = Configuration.GetMap(key); ; 148 | 149 | // var val = _obj.GetType().GetProperty(currentMap.GetPrimaryKey()).GetValue(_obj); 150 | // string whereConditionStr = relationship.GetForeignKey() + " = " + val; 151 | 152 | // SqlBuilder qb = new SqlBuilder(obj); 153 | // string sql = qb.Select().Where(whereConditionStr).ToString(); 154 | // _graphSql += Environment.NewLine + sql; 155 | // } 156 | //} 157 | 158 | //return this; 159 | } 160 | 161 | public SqlBuilder Update() 162 | { 163 | createTask(SqlBuilderTask.QueryTypeEnum.Update); 164 | return this; 165 | } 166 | 167 | public SqlBuilder Insert() 168 | { 169 | createTask(SqlBuilderTask.QueryTypeEnum.Insert); 170 | return this; 171 | } 172 | 173 | public SqlBuilder Delete() 174 | { 175 | createTask(SqlBuilderTask.QueryTypeEnum.Delete); 176 | return this; 177 | } 178 | 179 | public SqlBuilder NoSemicolon() 180 | { 181 | currentTask.EndWithSemicolon = false; 182 | return this; 183 | } 184 | 185 | //private SqlBuilder buildSqlStatement(object obj, SqlBuilderTask.QueryTypeEnum queryType, string tableName, bool? fullGraph, bool? pluralizeTableNames, IPocoSqlMapping map) 186 | private SqlBuilder buildSqlStatement(object obj, SqlBuilderTask task) 187 | { 188 | if (task.QueryType == SqlBuilderTask.QueryTypeEnum.SelectScopeIdentity) 189 | { 190 | task.SqlResult = "select scope_identity()"; 191 | return this; 192 | } 193 | else if (task.QueryType == SqlBuilderTask.QueryTypeEnum.SelectIdentity) 194 | { 195 | task.SqlResult = "select @@identity"; 196 | return this; 197 | } 198 | 199 | IPocoSqlMapping map = null; 200 | string tableName = null; 201 | 202 | if (Configuration.Comment) 203 | task.SqlResult = getComment(obj); 204 | 205 | if (task.Map == null) 206 | map = getMapping(obj); 207 | 208 | if (map != null) 209 | { 210 | // 211 | // Custom query 212 | // 213 | var customQuery = getCustomQuery(task.QueryType, map); 214 | if (!String.IsNullOrEmpty(customQuery)) 215 | { 216 | task.SqlResult += customQuery; 217 | if (task.SqlResult.EndsWith(";")) currentTask.EndWithSemicolon = false; 218 | return this; // if it's a custom query no other thing needs (the user knew in advanced what he wanted) to be done and the result is returned 219 | } 220 | 221 | // 222 | // Stored Procedures mappings 223 | // 224 | var spMappings = map.GetStoredProceduresMappings(); 225 | if (spMappings != null) 226 | { 227 | PocoSqlStoredProcedureMap spMap = getStoredProcedureMap(spMappings, task.QueryType); 228 | if (spMap != null) 229 | { 230 | string spName = getStoredProcedureName(spMap, obj, task.QueryType); 231 | task.SqlResult += String.Format("{0}{1}{2}", 232 | spMap.Execution ? "exec " : String.Empty, 233 | spName, 234 | spMap.Parameters ? getQueryFields(task.QueryType, map) : String.Empty); 235 | if (!spMap.Execution && !spMap.Parameters) currentTask.EndWithSemicolon = false; 236 | return this; 237 | } 238 | } 239 | 240 | if (task.QueryType != SqlBuilderTask.QueryTypeEnum.Select && map.GetIsVirtual()) 241 | throw new CantUpdateVirtualException(); 242 | 243 | if (String.IsNullOrEmpty(task.TableName)) 244 | tableName = map.GetTableName(); 245 | } 246 | 247 | if (String.IsNullOrEmpty(tableName)) 248 | tableName = obj.GetType().Name; 249 | 250 | if ((map == null || (map != null && String.IsNullOrEmpty(map.GetTableName()))) && Configuration.IsPluralizeTableNames) 251 | { 252 | tableName = tableName.Pluralize(); 253 | } 254 | 255 | switch (task.QueryType) 256 | { 257 | case SqlBuilderTask.QueryTypeEnum.Select: 258 | task.SqlResult += String.Format("select {0} from {1}", getQueryFields(SqlBuilderTask.QueryTypeEnum.Select, map), tableName); 259 | break; 260 | case SqlBuilderTask.QueryTypeEnum.Insert: 261 | task.SqlResult += String.Format("insert into {0} {1}", tableName, getQueryFields(SqlBuilderTask.QueryTypeEnum.Insert, map)); 262 | break; 263 | case SqlBuilderTask.QueryTypeEnum.Update: 264 | task.SqlResult += String.Format("update {0} set {1}", tableName, getQueryFields(SqlBuilderTask.QueryTypeEnum.Update, map)); 265 | break; 266 | case SqlBuilderTask.QueryTypeEnum.Delete: 267 | task.SqlResult += String.Format("delete from {0}", tableName); 268 | string primaryKey = getPrimaryKey(_obj); 269 | string deleteWhereValue = "@" + primaryKey; 270 | if (Configuration.ValuesInQueies) 271 | deleteWhereValue = getPropertyValueAsSql(_obj, primaryKey); 272 | this.Where(String.Format("{0} = {1}", primaryKey, deleteWhereValue)); 273 | break; 274 | case SqlBuilderTask.QueryTypeEnum.StoredProcedure: 275 | var queryFields = String.Empty; 276 | var execCmd = String.Empty; 277 | task.SqlResult += String.Format("exec {0} {1}", tableName, getQueryFields(SqlBuilderTask.QueryTypeEnum.StoredProcedure, map)); 278 | break; 279 | } 280 | 281 | return this; 282 | } 283 | 284 | private PocoSqlStoredProcedureMap getStoredProcedureMap(PocoSqlStoredProceduresMapping spMappings, SqlBuilderTask.QueryTypeEnum queryType) 285 | { 286 | switch (queryType) 287 | { 288 | case SqlBuilderTask.QueryTypeEnum.Select: 289 | return spMappings.SelectMap; 290 | case SqlBuilderTask.QueryTypeEnum.Insert: 291 | return spMappings.InsertMap; 292 | case SqlBuilderTask.QueryTypeEnum.Update: 293 | return spMappings.UpdateMap; 294 | case SqlBuilderTask.QueryTypeEnum.Delete: 295 | return spMappings.DeleteMap; 296 | default: 297 | return null; 298 | } 299 | } 300 | 301 | private string getComment(object obj) 302 | { 303 | return String.Format( 304 | "/*{0}Poco.Sql{0}Time: {1}{0}Object: {2}{0}*/{0}", 305 | Environment.NewLine, 306 | DateTime.Now, 307 | obj.GetType().FullName 308 | ); 309 | } 310 | 311 | private string getCustomQuery(SqlBuilderTask.QueryTypeEnum queryType, IPocoSqlMapping map) 312 | { 313 | string customQuery = null; 314 | var customMappings = map.GetCustomMappings(); 315 | if (customMappings != null) 316 | { 317 | switch (queryType) 318 | { 319 | case SqlBuilderTask.QueryTypeEnum.Select: 320 | customQuery = customMappings.SelectQuery; 321 | break; 322 | case SqlBuilderTask.QueryTypeEnum.Insert: 323 | customQuery = customMappings.InsertQuery; 324 | break; 325 | case SqlBuilderTask.QueryTypeEnum.Update: 326 | customQuery = customMappings.UpdateQuery; 327 | break; 328 | case SqlBuilderTask.QueryTypeEnum.Delete: 329 | customQuery = customMappings.DeleteQuery; 330 | break; 331 | } 332 | } 333 | return customQuery; 334 | } 335 | 336 | private string getQueryFields(SqlBuilderTask.QueryTypeEnum queryType, IPocoSqlMapping map) 337 | { 338 | IEnumerable propertyInfos = _obj.GetType().GetRuntimeProperties(); 339 | 340 | string primaryKey = null; 341 | 342 | if (queryType == SqlBuilderTask.QueryTypeEnum.Update || queryType == SqlBuilderTask.QueryTypeEnum.Insert) 343 | primaryKey = getPrimaryKey(_obj); 344 | 345 | StringBuilder allFields = new StringBuilder(); 346 | StringBuilder insertValues = new StringBuilder(); 347 | 348 | foreach (PropertyInfo propertyInfo in propertyInfos.Where(p => p.PropertyType.FullName.StartsWith("System") && !p.PropertyType.FullName.StartsWith("System.Collections"))) // only loop on objects that are not custom class 349 | { 350 | string 351 | dbSelect = null, 352 | fieldName = null, 353 | dbColumnName = null; 354 | 355 | if (map != null) 356 | { 357 | PropertyMap propertyMap = map.GetMapping(propertyInfo.Name); 358 | if (propertyMap != null) 359 | { 360 | if (!propertyMap.Ignored) 361 | { 362 | if (!propertyMap.ColumnName.Equals(propertyInfo.Name)) 363 | { 364 | if (queryType == SqlBuilderTask.QueryTypeEnum.Select) 365 | dbSelect = String.Format("{0} as {1}", 366 | propertyMap.ColumnName, 367 | propertyInfo.Name); 368 | fieldName = propertyInfo.Name; 369 | dbColumnName = propertyMap.ColumnName; 370 | } 371 | } 372 | else 373 | { 374 | dbSelect = String.Empty; 375 | } 376 | } 377 | } 378 | 379 | if (String.IsNullOrEmpty(dbSelect)) 380 | dbSelect = fieldName = dbColumnName = propertyInfo.Name; 381 | 382 | if (fieldName == primaryKey) 383 | { 384 | if (queryType == SqlBuilderTask.QueryTypeEnum.Update) 385 | { 386 | var property = _obj.GetType().GetRuntimeProperty(dbColumnName); 387 | string val = "@" + primaryKey; 388 | if (Configuration.ValuesInQueies) 389 | property.GetValue(_obj).ToString(); 390 | this.Where(primaryKey + " = " + val); 391 | } 392 | 393 | if (queryType == SqlBuilderTask.QueryTypeEnum.Update || (queryType == SqlBuilderTask.QueryTypeEnum.Insert && map.GetPrimaryAutoGenerated())) 394 | continue; 395 | } 396 | 397 | switch(queryType) 398 | { 399 | case SqlBuilderTask.QueryTypeEnum.Select: 400 | allFields.Append((allFields.Length > 0 && !String.IsNullOrEmpty(fieldName) ? ", " : String.Empty) + dbSelect); 401 | break; 402 | 403 | case SqlBuilderTask.QueryTypeEnum.Insert: 404 | if (!String.IsNullOrEmpty(fieldName)) 405 | { 406 | string insertVal; 407 | if (Configuration.ValuesInQueies) 408 | insertVal = getPropertyValueAsSql(_obj, fieldName); 409 | else 410 | insertVal = "@" + fieldName; 411 | 412 | allFields.Append((allFields.Length > 0 ? ", " : String.Empty) + dbSelect); 413 | insertValues.Append((insertValues.Length > 0 ? ", " : String.Empty) + insertVal); 414 | } 415 | break; 416 | 417 | case SqlBuilderTask.QueryTypeEnum.Update: 418 | case SqlBuilderTask.QueryTypeEnum.StoredProcedure: 419 | string updateVal; 420 | if (Configuration.ValuesInQueies) 421 | updateVal = getPropertyValueAsSql(_obj, fieldName, true); 422 | else 423 | updateVal = "@" + fieldName; 424 | 425 | allFields.Append((allFields.Length > 0 && !String.IsNullOrEmpty(fieldName) ? ", " : String.Empty) + dbColumnName + " = " + updateVal); 426 | break; 427 | 428 | case SqlBuilderTask.QueryTypeEnum.Delete: 429 | 430 | break; 431 | } 432 | } 433 | 434 | if (queryType == SqlBuilderTask.QueryTypeEnum.Insert) 435 | return String.Format("({0}) values({1})", allFields, insertValues); 436 | else 437 | return allFields.ToString(); 438 | } 439 | 440 | private string getPropertyValueAsSql(object obj, string propertyName) 441 | { 442 | return getPropertyValueAsSql(obj, propertyName, false); 443 | } 444 | 445 | private string getPropertyValueAsSql(object obj, string propertyName, bool cast) 446 | { 447 | PropertyInfo property = obj.GetType().GetRuntimeProperty(propertyName); 448 | string result = property.GetValue(_obj).ToString(); 449 | 450 | if ((property.PropertyType == typeof(string) || !cast) && property.PropertyType != typeof(int)) 451 | result = "'" + result + "'"; 452 | else if (property.PropertyType == typeof(DateTime)) 453 | result = "cast('" + result + "' as datetime)"; 454 | 455 | return result; 456 | } 457 | 458 | private string getStoredProcedureName(PocoSqlStoredProcedureMap spMap, object obj, SqlBuilderTask.QueryTypeEnum queryType) 459 | { 460 | if (spMap == null) return String.Empty; 461 | if (String.IsNullOrEmpty(spMap.Name)) 462 | return String.Format("{0}{1}_{2}", Configuration.StoredProceduresPrefix, obj.GetType().Name, queryType.ToString()); 463 | 464 | return spMap.Name; 465 | } 466 | 467 | private IPocoSqlMapping getMapping(object obj) 468 | { 469 | IPocoSqlMapping map = null; 470 | string key = obj.GetType().FullName; 471 | if (Configuration.HasMap(key)) 472 | map = Configuration.GetMap(key); 473 | return map; 474 | } 475 | 476 | #region Join 477 | public SqlBuilder Join(Expression> on) 478 | { 479 | return Join(typeof(T).Name, on); 480 | } 481 | 482 | public SqlBuilder Join(string tableName, Expression> on) 483 | { 484 | throw new NotImplementedException(); 485 | return this; 486 | } 487 | #endregion 488 | 489 | #region Where 490 | public SqlBuilder Where(string condition) 491 | { 492 | //TODO: make sure update statements can't have a a where clause 493 | currentTask.WhereStrings.Add(condition); 494 | return this; 495 | } 496 | 497 | public SqlBuilder Where(Expression> condition) 498 | { 499 | //TODO: make sure update statements can't have a a where clause 500 | currentTask.WhereExpressions.Add(condition.Body); 501 | //_where += " where " + ExpressionEvaluator.Eval(condition.Body, Configuration.ValuesInQueies); 502 | return this; 503 | } 504 | #endregion 505 | 506 | private string getPrimaryKey(object obj) 507 | { 508 | var map = getMapping(_obj); 509 | if (map != null && !String.IsNullOrEmpty(map.GetPrimaryKey())) 510 | return map.GetPrimaryKey(); // return a mapped primary key 511 | 512 | // check by convension 513 | PropertyInfo property = null; 514 | property = obj.GetType().GetRuntimeProperties().Where(p => p.Name.ToLower() == "id").FirstOrDefault(); 515 | if (property != null) 516 | return property.Name; 517 | 518 | property = obj.GetType().GetRuntimeProperties().Where(p => p.Name.ToLower() == obj.GetType().Name.ToLower() + "id").FirstOrDefault(); 519 | if (property != null) 520 | return property.Name; 521 | 522 | return null; 523 | } 524 | 525 | private void buildWhereCondition(object _obj, SqlBuilderTask task) 526 | { 527 | if (task.WhereStrings.Count > 0) 528 | { 529 | foreach (var whereString in task.WhereStrings) 530 | { 531 | task.WhereCondition += String.IsNullOrEmpty(task.WhereCondition) 532 | ? " where (" + whereString + ")" 533 | : " and (" + whereString + ")"; 534 | } 535 | } 536 | 537 | if (task.WhereExpressions.Count == 0) return; 538 | foreach (var whereExpression in task.WhereExpressions) 539 | { 540 | var expressionStr = ExpressionEvaluator.Eval(whereExpression, Configuration.ValuesInQueies); 541 | task.WhereCondition += String.IsNullOrEmpty(task.WhereCondition) 542 | ? " where (" + expressionStr + ")" 543 | : " and (" + expressionStr + ")"; 544 | } 545 | } 546 | 547 | public override string ToString() 548 | { 549 | return getSqlStatement(); 550 | } 551 | 552 | public string ToSQL() 553 | { 554 | return getSqlStatement(); 555 | } 556 | 557 | private string getSqlStatement() 558 | { 559 | if (_tasks.Count == 0) // there must be at least one task 560 | throw new NoSqlBuilderTaskFound(); 561 | 562 | StringBuilder result = new StringBuilder(); 563 | foreach (var task in _tasks) 564 | { 565 | buildSqlStatement(_obj, task); 566 | buildWhereCondition(_obj, task); 567 | 568 | var sql = String.Format("{0}{1}{2}", 569 | task.SqlResult, 570 | task.WhereCondition, 571 | task.EndWithSemicolon ? ";" : String.Empty); 572 | 573 | result.Append(sql); 574 | } 575 | 576 | return result.ToString(); 577 | } 578 | } 579 | } 580 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/SqlBuilderTask.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq.Expressions; 3 | using Poco.Sql.NetCore.Interfaces; 4 | 5 | namespace Poco.Sql.NetCore 6 | { 7 | class SqlBuilderTask 8 | { 9 | internal enum QueryTypeEnum { Select, Insert, Update, Delete, StoredProcedure, CreateTable, AlterTable, DropTable, TruncateTable, PreDefined, QueryByName, SelectIdentity, SelectScopeIdentity } 10 | 11 | public QueryTypeEnum QueryType { get; set; } 12 | public string TableName { get; set; } 13 | public string QueryName { get; set; } 14 | public List WhereStrings { get; set; } 15 | public List WhereExpressions { get; set; } 16 | public object PrimaryKeyValue { get; set; } 17 | public string SqlResult { get; set; } 18 | public string WhereCondition { get; set; } 19 | public IPocoSqlMapping Map { get; set; } 20 | public bool EndWithSemicolon { get; set; } 21 | 22 | public SqlBuilderTask() 23 | { 24 | WhereStrings = new List(); 25 | WhereExpressions = new List(); 26 | EndWithSemicolon = true; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/StatementsCreator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Poco.Sql.NetCore 4 | { 5 | public class StatementsCreator 6 | { 7 | public static SqlBuilder Create() 8 | { 9 | var dummy = (T) Activator.CreateInstance(typeof (T)); 10 | return new SqlBuilder(dummy); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Poco.Sql.NetCore/ValuesObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.SqlTypes; 4 | using System.Dynamic; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text.RegularExpressions; 8 | 9 | namespace Poco.Sql.NetCore 10 | { 11 | public class ValuesObject 12 | { 13 | private static readonly SqlDateTime _smallDateTimeMinValue = new SqlDateTime(new DateTime(1900, 01, 01, 00, 00, 00)); 14 | 15 | public static object Create(params object[] args) 16 | { 17 | dynamic obj = new ExpandoObject(); 18 | 19 | List sqlParams = GetPramsFromSqlString(args); 20 | int startPos = sqlParams == null ? 0 : 1; // if we have sqlParams that means that the first agrument is an sql string 21 | 22 | // loop over all objects that were sent for merging 23 | for (int i = startPos; i < args.Length; i++) 24 | { 25 | // get an object and make sure it's valid 26 | object currentObj = args[i]; 27 | if (currentObj == null) continue; 28 | 29 | IDictionary objDic = (IDictionary) obj; 30 | 31 | // loop over all elements of current object 32 | IEnumerable propertyInfos = currentObj.GetType().GetRuntimeProperties(); 33 | foreach ( 34 | PropertyInfo propertyInfo in 35 | propertyInfos.Where( 36 | p => 37 | p.PropertyType.GetTypeInfo().IsEnum || 38 | (p.PropertyType.FullName.StartsWith("System") && 39 | !p.PropertyType.FullName.StartsWith("System.Collections")))) 40 | // only loop on objects that are not custom class 41 | { 42 | if (objDic.ContainsKey(propertyInfo.Name)) 43 | continue; // same key can't be added twice (first key found will be used) 44 | 45 | if (sqlParams == null || sqlParams.Contains(propertyInfo.Name)) 46 | { 47 | var val = propertyInfo.GetValue(currentObj); 48 | if (propertyInfo.PropertyType == typeof (DateTime) && (DateTime) val == DateTime.MinValue) 49 | val = (DateTime) System.Data.SqlTypes.SqlDateTime.MinValue; 50 | 51 | objDic.Add(propertyInfo.Name, val); 52 | } 53 | } 54 | } 55 | 56 | return (object)obj; 57 | } 58 | 59 | private static object getDefaultValue(Type t) 60 | { 61 | if (t == typeof(DateTime)) 62 | return DateTime.MinValue; 63 | else if (t.GetTypeInfo().IsValueType) 64 | return Activator.CreateInstance(t); 65 | 66 | return null; 67 | } 68 | 69 | private static List GetPramsFromSqlString(object[] args) 70 | { 71 | List sqlParams = null; 72 | if (args.Length > 1 && args[0] is String) 73 | { 74 | sqlParams = new List(); 75 | 76 | string sql = args[0].ToString(); 77 | Regex regex = new Regex(@"(?<=@)([\w\-]+)"); 78 | var matches = regex.Matches(sql); 79 | 80 | for (int i = 0; i < matches.Count; i++) 81 | { 82 | var val = matches[i].Value; 83 | if (!sqlParams.Contains(val)) 84 | sqlParams.Add(matches[i].Value); 85 | } 86 | } 87 | return sqlParams; 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /Poco.Sql.NetCore/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-*", 3 | "title": "Poco.Sql.NetCore", 4 | "description": "Lightweight .NET Core library for generating SQL statements from plain objects with advanced features and mapping support", 5 | "authors": [ "Ophir Oren" ], 6 | "copyright": "Copyright (c) 2016 Ophir Oren", 7 | "packOptions": { 8 | "owners": [ "Ophir Oren" ], 9 | "projectUrl": "https://github.com/developer82/Poco.Sql.NetCore", 10 | "tags": [ "ORM", "DAL", "ado.net", "data", "recordset", "sql", "query", "generator", "batch", "database", "micro-orm", "data-mapper", "poco", "schema-less", "netstandard", "netcore", "net45" ], 11 | "licenseUrl": "https://github.com/developer82/Poco.Sql.NetCore/blob/master/LICENSE", 12 | "iconUrl": "https://github.com/developer82/Poco.Sql.NetCore/blob/master/Logo.png" 13 | }, 14 | "buildOptions": { 15 | "xmlDoc": true 16 | }, 17 | 18 | "dependencies": { 19 | "Humanizer.xproj": "2.1.0", 20 | "Microsoft.CSharp": "4.0.1", 21 | "NETStandard.Library": "1.6.0", 22 | "System.Data.SqlClient": "4.1.0", 23 | "System.Dynamic.Runtime": "4.0.11" 24 | }, 25 | 26 | "frameworks": { 27 | "netstandard1.6": { 28 | "imports": "dnxcore50" 29 | } 30 | }, 31 | 32 | "scripts": { 33 | "postcompile": [ 34 | "dotnet pack --no-build --configuration %compile:Configuration%" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Poco.Sql.NetCore](https://github.com/developer82/Poco.Sql.NetCore/blob/master/Logo.png) 2 | 3 | # Poco.Sql.NetCore 4 | ##### Auto generate SQL statements from .NET objects 5 | 6 | Poco.Sql.NetCore is a convertion of the original Poco.Sql project (https://github.com/developer82/Poco.Sql) to .NET Core. 7 | 8 | [![Build status](https://ci.appveyor.com/api/projects/status/cwohpnw3jdbkus2m?svg=true)](https://ci.appveyor.com/project/developer82/poco-sql-netcore) 9 | 10 | ## Installation 11 | 12 | Poco.Sql.NetCore is avilable via NuGet (https://www.nuget.org/packages/Poco.Sql.NetCore/1.0.0) 13 | 14 | `Install-Package Poco.Sql.NetCore` 15 | 16 | ## Quick Start 17 | 18 | Include the Poco.Sql extentions method namespace 19 | 20 | ``` 21 | using Poco.Sql.NetCore.Extensions; 22 | ``` 23 | 24 | Generate SQL statements from ANY object 25 | 26 | ``` 27 | myObject.PocoSql().Select().ToString(); 28 | myObject.PocoSql().Insert().ToString(); 29 | myObject.PocoSql().Update().ToString(); 30 | myObject.PocoSql().Delete().ToString(); 31 | ``` 32 | 33 | [Read the Quick Start guide](https://github.com/developer82/Poco.Sql.NetCore/wiki/Quick-Start) 34 | 35 | **It's that simple!** 36 | 37 | ## Configuration 38 | Confgiration can be executed only once in the application lifecycle. Once configured, it doesn't allow changing the configuration later on. 39 | 40 | Example configuration: 41 | ``` 42 | // PocoSql configuration 43 | Configuration.Initialize(config => 44 | { 45 | config.PluralizeTableNames(); 46 | config.SetStoreProcedurePrefix("stp_"); 47 | config.ShowComments(); 48 | config.InjectValuesInQueies(); 49 | config.SelectFullGraph(); 50 | config.AddMap(new EntityMap()); 51 | }); 52 | ``` 53 | [Read more about Poco.Sql.NetCore configuration](https://github.com/developer82/Poco.Sql.NetCore/wiki/Configuration) 54 | 55 | ## Object Mapping 56 | 57 | Poco.Sql.NetCore works out-of-the-box on any .NET class and without the need to configure or map anything. However, there might be cases where we would like to apply mapping on objects - map relationships between objects, map object properties to database fields, ignore properties, set custom table name for object, define stored procedures, and more... 58 | 59 | To allow such mapping, Poco.Sql.NetCore has a mapping object that helps you define mappings between your objects and the database. 60 | 61 | To create a mapping object, create a new class that inherits from `Poco.Sql.NetCore.PocoSqlMapping` 62 | 63 | ``` 64 | public class UserMap : PocoSqlMapping 65 | { 66 | public UserMap() 67 | { 68 | // mapping configuration 69 | } 70 | } 71 | ``` 72 | 73 | [Read more about Poco.Sql.NetCore mappings](https://github.com/developer82/Poco.Sql.NetCore/wiki/Object-Mapping) 74 | 75 | ## Values Object Creator 76 | 77 | To save the time and lines of code in writing these objects, Poco.Sql.NetCore has an helper class that knows how to create an object that's combined of your domain objects, and is specific to SQL statement. 78 | 79 | ``` 80 | var sql = "insert into Users(FirstName, LastName, DateOfBirth, LuckyNumber, IsRegistered) values(@FirstName, @LastName, @DateOfBirth, @LuckyNumber, @IsRegistered)"; 81 | var data = ValuesObject.Create(sql, myUserObject /* , ... */); 82 | ``` 83 | 84 | [Read more about Poco.Sql.NetCore Values Object Creator](https://github.com/developer82/Poco.Sql.NetCore/wiki/Values-Object-Creator) 85 | 86 | ## Further Reading 87 | 88 | I'm also on twitter! follow me [@supervill_dev82](https://twitter.com/supervill_dev82) 89 | 90 | ## License 91 | 92 | The MIT License (MIT) 93 | 94 | Copyright (c) 2014-2018 Ophir Oren 95 | 96 | Permission is hereby granted, free of charge, to any person obtaining a copy 97 | of this software and associated documentation files (the "Software"), to deal 98 | in the Software without restriction, including without limitation the rights 99 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 100 | copies of the Software, and to permit persons to whom the Software is 101 | furnished to do so, subject to the following conditions: 102 | 103 | The above copyright notice and this permission notice shall be included in 104 | all copies or substantial portions of the Software. 105 | 106 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 107 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 108 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 109 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 110 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 111 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 112 | THE SOFTWARE. 113 | --------------------------------------------------------------------------------