├── .gitattributes ├── .gitignore ├── LICENSE ├── Magicodes.DynamicSqlApi.sln ├── README.md ├── common.props ├── docs └── DynamicSqlApi.xmind ├── res ├── DynamicSqlApi.png ├── swaggerapi.png └── wechat.jpg └── src ├── Magicodes.DynamicSqlApi.All ├── Extensions.cs └── Magicodes.DynamicSqlApi.All.csproj ├── Magicodes.DynamicSqlApi.Core ├── CodeBuilder │ ├── ActionBuilderInfo.cs │ ├── ActionFieldInfo.cs │ ├── ActionInputInfo.cs │ ├── ActionInputTypes.cs │ ├── ActionOutputInfo.cs │ ├── CodeBuilderInfo.cs │ ├── ControllerBuilderInfo.cs │ └── DefaultCodeBuilder.cs ├── CodeBuilderBase.cs ├── DynamicApis │ ├── DynamicApiControllerAttribute.cs │ └── GenericTypeControllerFeatureProvider.cs ├── Extensions │ └── StringExtensions.cs ├── ICodeCompiler.cs ├── ISqlExecutor.cs ├── ITSqlParser.cs ├── Magicodes.DynamicSqlApi.Core.csproj ├── Models │ ├── TSqlOutputFieldInfo.cs │ └── TSqlParameterInfo.cs └── ServiceCollectionExtensions.cs ├── Magicodes.DynamicSqlApi.CsScript ├── CsScriptCodeCompiler.cs └── Magicodes.DynamicSqlApi.CsScript.csproj ├── Magicodes.DynamicSqlApi.Dapper ├── DapperSqlExecutor.cs └── Magicodes.DynamicSqlApi.Dapper.csproj ├── Magicodes.DynamicSqlApi.Sqlserver ├── GetSqlServerOutputListDto.cs ├── GetSqlServerParametersOutput.cs ├── Magicodes.DynamicSqlApi.SqlServer.csproj ├── SqlServerDbTypeMapperHelper.cs └── SqlServerTSqlParser.cs ├── Web2_2 ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── Web2_2.csproj ├── appsettings.Development.json ├── appsettings.json └── sqlMapper.xml ├── Web3_1 ├── HomeController.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── Web3_1.csproj ├── appsettings.Development.json ├── appsettings.json └── sqlMapper.xml └── Web6 ├── Controllers └── WeatherForecastController.cs ├── Data ├── AppDbContext.cs └── Models │ ├── ClassInfo.cs │ ├── GradeInfo.cs │ ├── MajorInfo.cs │ ├── StudentInfo.cs │ └── ValidationConsts.cs ├── Migrations ├── 20221205144119_Init.Designer.cs ├── 20221205144119_Init.cs └── AppDbContextModelSnapshot.cs ├── Program.cs ├── Properties └── launchSettings.json ├── WeatherForecast.cs ├── Web6.csproj ├── appsettings.Development.json ├── appsettings.json └── sqlMapper.xml /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 李文强 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 | -------------------------------------------------------------------------------- /Magicodes.DynamicSqlApi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33122.133 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magicodes.DynamicSqlApi.Core", "src\Magicodes.DynamicSqlApi.Core\Magicodes.DynamicSqlApi.Core.csproj", "{6D9BB541-7735-4437-AB4F-54FCB295873C}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magicodes.DynamicSqlApi.All", "src\Magicodes.DynamicSqlApi.All\Magicodes.DynamicSqlApi.All.csproj", "{83ED9533-2D98-458E-8EE2-96FA03641968}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magicodes.DynamicSqlApi.Dapper", "src\Magicodes.DynamicSqlApi.Dapper\Magicodes.DynamicSqlApi.Dapper.csproj", "{B2583B3E-9CE6-4E6E-B673-B3806A327BE6}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magicodes.DynamicSqlApi.CsScript", "src\Magicodes.DynamicSqlApi.CsScript\Magicodes.DynamicSqlApi.CsScript.csproj", "{44FB13A8-2BD3-40DF-BA2B-260F5388477B}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magicodes.DynamicSqlApi.SqlServer", "src\Magicodes.DynamicSqlApi.Sqlserver\Magicodes.DynamicSqlApi.SqlServer.csproj", "{BFAE08CC-7BAE-4C90-B162-EBFFE578F67B}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{F209EF50-996A-4A16-B326-FE92A494A4A8}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{291717B8-6165-41C2-ABFC-DE18ABD44E43}" 19 | ProjectSection(SolutionItems) = preProject 20 | common.props = common.props 21 | README.md = README.md 22 | EndProjectSection 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web6", "src\Web6\Web6.csproj", "{9FA44933-E89C-4C86-9476-3D90CFC18C37}" 25 | EndProject 26 | Global 27 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 28 | Debug|Any CPU = Debug|Any CPU 29 | Release|Any CPU = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {6D9BB541-7735-4437-AB4F-54FCB295873C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {6D9BB541-7735-4437-AB4F-54FCB295873C}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {6D9BB541-7735-4437-AB4F-54FCB295873C}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {6D9BB541-7735-4437-AB4F-54FCB295873C}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {83ED9533-2D98-458E-8EE2-96FA03641968}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {83ED9533-2D98-458E-8EE2-96FA03641968}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {83ED9533-2D98-458E-8EE2-96FA03641968}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {83ED9533-2D98-458E-8EE2-96FA03641968}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {B2583B3E-9CE6-4E6E-B673-B3806A327BE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {B2583B3E-9CE6-4E6E-B673-B3806A327BE6}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {B2583B3E-9CE6-4E6E-B673-B3806A327BE6}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {B2583B3E-9CE6-4E6E-B673-B3806A327BE6}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {44FB13A8-2BD3-40DF-BA2B-260F5388477B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {44FB13A8-2BD3-40DF-BA2B-260F5388477B}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {44FB13A8-2BD3-40DF-BA2B-260F5388477B}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {44FB13A8-2BD3-40DF-BA2B-260F5388477B}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {BFAE08CC-7BAE-4C90-B162-EBFFE578F67B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {BFAE08CC-7BAE-4C90-B162-EBFFE578F67B}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {BFAE08CC-7BAE-4C90-B162-EBFFE578F67B}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {BFAE08CC-7BAE-4C90-B162-EBFFE578F67B}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {9FA44933-E89C-4C86-9476-3D90CFC18C37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {9FA44933-E89C-4C86-9476-3D90CFC18C37}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {9FA44933-E89C-4C86-9476-3D90CFC18C37}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {9FA44933-E89C-4C86-9476-3D90CFC18C37}.Release|Any CPU.Build.0 = Release|Any CPU 56 | EndGlobalSection 57 | GlobalSection(SolutionProperties) = preSolution 58 | HideSolutionNode = FALSE 59 | EndGlobalSection 60 | GlobalSection(NestedProjects) = preSolution 61 | {9FA44933-E89C-4C86-9476-3D90CFC18C37} = {F209EF50-996A-4A16-B326-FE92A494A4A8} 62 | EndGlobalSection 63 | GlobalSection(ExtensibilityGlobals) = postSolution 64 | SolutionGuid = {7A744D7B-193A-431C-9830-327B791A8EEC} 65 | EndGlobalSection 66 | EndGlobal 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Magicodes.DynamicSqlApi 2 | 3 | 根据SQL自动解析生成动态API。 4 | 5 | [![Build Status](https://dev.azure.com/xinlaiopencode/Magicodes.DynamicSqlApi/_apis/build/status/Magicodes.DynamicSqlApi-ASP.NET%20Core-CI?branchName=master)](https://dev.azure.com/xinlaiopencode/Magicodes.DynamicSqlApi/_build/latest?definitionId=9&branchName=master) 6 | 7 | ## 特点 8 | 9 | ![总体说明](./res/DynamicSqlApi.png) 10 | 11 | ### TODO 12 | 13 | - [ ] 使用模板语法生成API控制器:[scriban/scriban](https://github.com/scriban/scriban) 14 | - [x] API注释 15 | - [ ] 基于数据表配置CURD 16 | - [x] 多个数据库连接配置 17 | - [x] 命名空间隔离(由于不支持命名空间定义,使用子类完成) 18 | - [ ] 全局配置 19 | 20 | ### 配置 21 | 22 | ````xml 23 | 24 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | SELECT TOP 1 * FROM [dbo].[Students] 36 | WHERE [Id] = @Id 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | INSERT INTO [dbo].[Students] 45 | ([Name],[IdCard],[StudentCode],[Phone],[Nation],[Guardian],[GuardianPhone],[Address]) 46 | VALUES 47 | (@Name,@IdCard,@StudentCode,@Phone,@Nation,@Guardian,@GuardianPhone,@Address) 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | select top (select (@PageSize)) * 56 | from (select row_number() over(order by id) as rownumber,* 57 | from [dbo].[Students]) temp_row 58 | where rownumber>(@SkipCount) 59 | 60 | 61 | 62 | 63 | 64 | 65 | SELECT TOP (1000) * 66 | FROM [dbo].[Classes] 67 | 68 | 69 | 70 | 71 | 72 | 73 | SELECT TOP (@PageSize) * 74 | FROM [dbo].[Devices] 75 | 76 | 77 | 78 | 79 | ```` 80 | 81 | ### 结果 82 | 83 | ![结果](./res/swaggerapi.png) 84 | 85 | ## 相关官方Nuget包 86 | 87 | | 名称 | Nuget | 88 | |----------|:-------------:| 89 | | Magicodes.DynamicSqlApi.Core | [![NuGet](https://buildstats.info/nuget/Magicodes.DynamicSqlApi.Core)](https://www.nuget.org/packages/Magicodes.DynamicSqlApi.Core) | 90 | | Magicodes.DynamicSqlApi.All | [![NuGet](https://buildstats.info/nuget/Magicodes.DynamicSqlApi.All)](https://www.nuget.org/packages/Magicodes.DynamicSqlApi.All) | 91 | | Magicodes.DynamicSqlApi.CsScript | [![NuGet](https://buildstats.info/nuget/Magicodes.DynamicSqlApi.CsScript)](https://www.nuget.org/packages/Magicodes.DynamicSqlApi.CsScript) | 92 | | Magicodes.DynamicSqlApi.Dapper | [![NuGet](https://buildstats.info/nuget/Magicodes.DynamicSqlApi.Dapper)](https://www.nuget.org/packages/Magicodes.DynamicSqlApi.Dapper) | 93 | | Magicodes.DynamicSqlApi.SqlServer | [![NuGet](https://buildstats.info/nuget/Magicodes.DynamicSqlApi.SqlServer)](https://www.nuget.org/packages/Magicodes.DynamicSqlApi.SqlServer) | 94 | 95 | ## VNext 96 | 97 | > 以下内容均已有思路,但是缺乏精力,因此虚席待PR,有兴趣的朋友可以参与进来,多多交流。 98 | 99 | 见上图: 100 | 101 | - [x] API分组 102 | - [ ] API权限控制 103 | - [ ] API文档以及注释 104 | - [ ] 导入导出 105 | - [ ] HTTP状态码 106 | - [ ] 日志 107 | - [ ] 数据验证 108 | - [ ] 数组支持 109 | 110 | 111 | ## 开始使用 112 | 113 | 1. 引用Nuget包"Magicodes.DynamicSqlApi.All" 114 | 115 | | 名称 | 说明 | Nuget | 116 | |----------|:-------------:|:-------------:| 117 | | Magicodes.DynamicSqlApi.All | Magicodes.DynamicSqlApi 默认实现| [![NuGet](https://buildstats.info/nuget/Magicodes.DynamicSqlApi.All)](https://www.nuget.org/packages/Magicodes.DynamicSqlApi.All) | 118 | 119 | 2. 添加配置文件“sqlMapper.xml” 120 | 121 | 配置文件默认为“sqlMapper.xml”,配置参考下文: 122 | ````xml 123 | 124 | 125 | 126 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | SELECT TOP 1 * FROM [dbo].[AbpAuditLogs] 136 | WHERE [Id] = @Id 137 | 138 | 139 | 140 | 141 | 142 | 143 | SELECT TOP (1000) * 144 | FROM [dbo].[AbpUsers] 145 | 146 | 147 | 148 | 149 | ```` 150 | 151 | 如上述配置所示,仅需配置SQL语句即可,参数和结果列表全由Magicodes.DynamicSqlApi自动解析生成。Name是必须的。 152 | 153 | 3. 配置ASP.NET Core工程 154 | 155 | 添加配置: 156 | 157 | ````C# 158 | public class Program 159 | { 160 | public static void Main(string[] args) 161 | { 162 | CreateHostBuilder(args).Build().Run(); 163 | } 164 | 165 | public static IHostBuilder CreateHostBuilder(string[] args) => 166 | Host.CreateDefaultBuilder(args) 167 | .ConfigureAppConfiguration((hostingContext, config) => 168 | { 169 | var env = hostingContext.HostingEnvironment; 170 | //根据环境变量加载不同的JSON配置 171 | config.AddJsonFile("appsettings.json", true, true) 172 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", 173 | true, true); 174 | //从环境变量添加配置 175 | config.AddEnvironmentVariables(); 176 | config.AddXmlFile("sqlMapper.xml", true, false); 177 | }) 178 | .ConfigureWebHostDefaults(webBuilder => 179 | { 180 | webBuilder.UseStartup(); 181 | }); 182 | } 183 | ```` 184 | 185 | 启用DynamicSqlApi: 186 | 187 | ````C# 188 | public void ConfigureServices(IServiceCollection services) 189 | { 190 | services.AddAllDynamicSqlApi(Configuration["ConnectionStrings:Default"]); 191 | } 192 | 193 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 194 | { 195 | app.UseDynamicSqlApi(); 196 | } 197 | ```` 198 | 199 | ## 联系我们 200 | 201 | > ### 订阅号 202 | 203 | 关注“麦扣聊技术”订阅号可以获得最新文章、教程、文档: 204 | 205 | ![](./res/wechat.jpg "麦扣聊技术") 206 | 207 | > ### QQ群 208 | 209 | - 编程交流群<85318032> 210 | 211 | - 产品交流群<897857351> 212 | 213 | > ### 文档官网&官方博客 214 | 215 | - 文档官网: 216 | - 博客: 217 | 218 | 219 | > ### 其他开源库 220 | 221 | - 222 | - 223 | 224 | -------------------------------------------------------------------------------- /common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0.4 4 | 5 | 6 | 雪雁 7 | 湖南心莱信息科技有限公司 8 | 麦扣 9 | https://docs.xin-lai.com/ 10 | https://github.com/xin-lai/Magicodes.DynamicSqlApi 11 | 12 | 根据SQL自动构建动态WebAPI。 13 | 官方网址:http://docs.xin-lai.com 14 | 开源库地址:https://github.com/xin-lai 15 | 博客地址:http://www.cnblogs.com/codelove/ 16 | 交流QQ群:85318032 17 | 18 | 19 | 20 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml 21 | 22 | -------------------------------------------------------------------------------- /docs/DynamicSqlApi.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xin-lai/Magicodes.DynamicSqlApi/7d5c4890a2aa704aa36a7ee7b579bf4fe1c919d3/docs/DynamicSqlApi.xmind -------------------------------------------------------------------------------- /res/DynamicSqlApi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xin-lai/Magicodes.DynamicSqlApi/7d5c4890a2aa704aa36a7ee7b579bf4fe1c919d3/res/DynamicSqlApi.png -------------------------------------------------------------------------------- /res/swaggerapi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xin-lai/Magicodes.DynamicSqlApi/7d5c4890a2aa704aa36a7ee7b579bf4fe1c919d3/res/swaggerapi.png -------------------------------------------------------------------------------- /res/wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xin-lai/Magicodes.DynamicSqlApi/7d5c4890a2aa704aa36a7ee7b579bf4fe1c919d3/res/wechat.jpg -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.All/Extensions.cs: -------------------------------------------------------------------------------- 1 | using Magicodes.DynamicSqlApi.Core; 2 | using Magicodes.DynamicSqlApi.Core.CodeBuilder; 3 | using Magicodes.DynamicSqlApi.Core.DynamicApis; 4 | using Magicodes.DynamicSqlApi.CsScript; 5 | using Magicodes.DynamicSqlApi.Dapper; 6 | using Magicodes.DynamicSqlApi.Sqlserver; 7 | using Microsoft.AspNetCore.Builder; 8 | using Microsoft.Extensions.DependencyInjection; 9 | 10 | namespace Magicodes.DynamicSqlApi.All 11 | { 12 | public static class Extensions 13 | { 14 | public static void AddAllDynamicSqlApi(this IServiceCollection services, string connectionString, string sqlMapperFileName = "sqlMapper.xml") 15 | { 16 | services.AddDynamicSqlApi(connectionString, sqlMapperFileName); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.All/Magicodes.DynamicSqlApi.All.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/CodeBuilder/ActionBuilderInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Magicodes.DynamicSqlApi.Core.CodeBuilder 2 | { 3 | /// 4 | /// 5 | /// 6 | public class ActionBuilderInfo 7 | { 8 | public string Name { get; set; } 9 | 10 | public string HttpRoute { get; set; } 11 | 12 | public ActionOutputInfo ActionOutputInfo { get; set; } 13 | 14 | /// 15 | /// 16 | /// 17 | public ActionInputInfo ActionInputInfo { get; set; } 18 | public string SqlTpl { get; set; } 19 | 20 | public string Comment { get; set; } 21 | public string HttpMethod { get; internal set; } 22 | 23 | /// 24 | /// 是否存在返回值 25 | /// 26 | public bool HasReturnValue { get; set; } 27 | 28 | /// 29 | /// 数据库连接 30 | /// 31 | public string ConnectionString { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/CodeBuilder/ActionFieldInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Magicodes.DynamicSqlApi.Core.CodeBuilder 2 | { 3 | public class ActionFieldInfo 4 | { 5 | public string Name { get; set; } 6 | 7 | public string TypeName { get; set; } 8 | 9 | public bool? AllowNullable { get; set; } 10 | 11 | public object DefaultValue { get; set; } 12 | 13 | public string Comment { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/CodeBuilder/ActionInputInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Magicodes.DynamicSqlApi.Core.CodeBuilder 4 | { 5 | public class ActionInputInfo 6 | { 7 | public string BindFrom { get; set; } 8 | 9 | public ActionInputTypes ActionInputType { get; set; } = ActionInputTypes.None; 10 | 11 | public List ActionFieldInfos { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/CodeBuilder/ActionInputTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Magicodes.DynamicSqlApi.Core.CodeBuilder 2 | { 3 | public enum ActionInputTypes 4 | { 5 | None, 6 | Object, 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/CodeBuilder/ActionOutputInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Magicodes.DynamicSqlApi.Core.CodeBuilder 4 | { 5 | public class ActionOutputInfo 6 | { 7 | public ActionOutputTypes ActionOutputType { get; set; } = ActionOutputTypes.None; 8 | 9 | public List ActionFieldInfos { get; set; } 10 | } 11 | 12 | public enum ActionOutputTypes 13 | { 14 | None, 15 | List, 16 | } 17 | } -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/CodeBuilder/CodeBuilderInfo.cs: -------------------------------------------------------------------------------- 1 | using Magicodes.DynamicSqlApi.Core.DynamicApis; 2 | using Microsoft.Extensions.Configuration; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace Magicodes.DynamicSqlApi.Core.CodeBuilder 8 | { 9 | /// 10 | /// 代码构建信息 11 | /// 12 | public class CodeBuilderInfo 13 | { 14 | /// 15 | /// 命名空间列表 16 | /// 17 | public List Namespaces { get; set; } = new List() 18 | { 19 | "System", 20 | "System.Collections.Generic", 21 | "System.Linq", 22 | "System.Threading.Tasks", 23 | "Microsoft.AspNetCore.Mvc", 24 | "Microsoft.Extensions.Logging", 25 | "Swashbuckle.AspNetCore.Annotations", 26 | typeof(ISqlExecutor).Namespace, 27 | typeof(IConfiguration).Namespace, 28 | typeof(DynamicApiControllerAttribute).Namespace 29 | }; 30 | 31 | /// 32 | /// 控制器构建信息 33 | /// 34 | public List ControllerBuilderInfos { get; set; } = new List(); 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/CodeBuilder/ControllerBuilderInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Magicodes.DynamicSqlApi.Core.CodeBuilder 4 | { 5 | /// 6 | /// 控制器构建信息列表 7 | /// 8 | public class ControllerBuilderInfo 9 | { 10 | /// 11 | /// 路由 12 | /// 13 | public string Route { get; set; } 14 | 15 | /// 16 | /// 控制器名称 17 | /// 18 | public string Name { get; set; } 19 | 20 | /// 21 | /// 原始Key 22 | /// 23 | public string Key { get; set; } 24 | 25 | /// 26 | /// 注释 27 | /// 28 | public string Comment { get; set; } 29 | 30 | /// 31 | /// Action列表 32 | /// 33 | public List ActionBuilderInfos { get; set; } = new List(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/CodeBuilder/DefaultCodeBuilder.cs: -------------------------------------------------------------------------------- 1 | using Magicodes.DynamicSqlApi.Core.DynamicApis; 2 | using Microsoft.Extensions.Configuration; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Magicodes.DynamicSqlApi.Core.CodeBuilder 9 | { 10 | /// 11 | /// 默认的代码构建 12 | /// 13 | public class DefaultCodeBuilder : CodeBuilderBase 14 | { 15 | public DefaultCodeBuilder(IConfiguration configuration, ITSqlParser tSqlParser) : base(configuration, tSqlParser) 16 | { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/CodeBuilderBase.cs: -------------------------------------------------------------------------------- 1 | using Magicodes.DynamicSqlApi.Core.CodeBuilder; 2 | using Magicodes.DynamicSqlApi.Core.DynamicApis; 3 | using Magicodes.DynamicSqlApi.Core.Extensions; 4 | using Microsoft.Extensions.Configuration; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | namespace Magicodes.DynamicSqlApi.Core 11 | { 12 | /// 13 | /// 代码构建器基类 14 | /// 15 | public abstract class CodeBuilderBase 16 | { 17 | public CodeBuilderBase(IConfiguration configuration, ITSqlParser tSqlParser) 18 | { 19 | Configuration = configuration; 20 | TSqlParser = tSqlParser; 21 | } 22 | 23 | public IConfiguration Configuration { get; } 24 | public ITSqlParser TSqlParser { get; } 25 | public CodeBuilderInfo CodeBuilderInfo { get; set; } 26 | 27 | /// 28 | /// 读取配置创建构建对象 29 | /// 30 | /// 31 | public virtual CodeBuilderInfo CreateCodeBuilderInfo() 32 | { 33 | var codeBuilderInfo = new CodeBuilderInfo(); 34 | CodeBuilderInfo = codeBuilderInfo; 35 | foreach (var group in Configuration.GetSection("SqlApis").GetChildren()) 36 | { 37 | var controllerBuilderInfo = new ControllerBuilderInfo() 38 | { 39 | Name = group.Key, 40 | Route = "api/" + group.Key.ToCamelCase(), 41 | Key = group.Key, 42 | Comment = group["Comment"], 43 | }; 44 | 45 | foreach (var sqlApi in group.GetSection("SqlApi").GetChildren()) 46 | { 47 | var actionBuilderInfo = CreateActionBuilderInfo(sqlApi, out var sqlTpl); 48 | 49 | //设置参数绑定方式 50 | SetHttpMethodAndBindFrom(sqlApi, actionBuilderInfo); 51 | controllerBuilderInfo.ActionBuilderInfos.Add(actionBuilderInfo); 52 | 53 | SetActionInputFieldInfosFromSql(sqlTpl, actionBuilderInfo); 54 | SetActionInputFieldInfosFromConfig(sqlApi, actionBuilderInfo); 55 | 56 | if (actionBuilderInfo.ActionInputInfo.ActionFieldInfos.Any()) 57 | { 58 | actionBuilderInfo.ActionInputInfo.ActionInputType = ActionInputTypes.Object; 59 | } 60 | 61 | SetActionOutputFieldInfosFromSql(sqlTpl, actionBuilderInfo); 62 | SetActionOutputFieldInfosFromConfig(sqlApi, actionBuilderInfo); 63 | 64 | if (actionBuilderInfo.ActionOutputInfo.ActionFieldInfos.Any()) 65 | { 66 | actionBuilderInfo.ActionOutputInfo.ActionOutputType = ActionOutputTypes.List; 67 | } 68 | 69 | } 70 | 71 | codeBuilderInfo.ControllerBuilderInfos.Add(controllerBuilderInfo); 72 | } 73 | return codeBuilderInfo; 74 | } 75 | 76 | /// 77 | /// 从配置中获取或重写输出参数 78 | /// 79 | /// 80 | /// 81 | protected virtual void SetActionOutputFieldInfosFromConfig(IConfigurationSection sqlApi, ActionBuilderInfo actionBuilderInfo) 82 | { 83 | if (sqlApi.GetSection("Output:Parameter").Exists()) 84 | { 85 | foreach (var par in sqlApi.GetSection("Output:Parameter").GetChildren()) 86 | { 87 | var name = par["Name"]; 88 | if (string.IsNullOrWhiteSpace(name)) 89 | continue; 90 | var comment = par["Comment"]; 91 | 92 | var type = par["Type"]; 93 | var defaultValue = par["DefaultValue"]; 94 | var allowNullable = par["AllowNullable"]; 95 | var actionFieldInfo = actionBuilderInfo.ActionOutputInfo.ActionFieldInfos.FirstOrDefault(p => p.Name == name); 96 | if (actionFieldInfo == null) 97 | { 98 | actionFieldInfo = new ActionFieldInfo() { Name = name }; 99 | actionBuilderInfo.ActionOutputInfo.ActionFieldInfos.Add(actionFieldInfo); 100 | } 101 | 102 | if (!string.IsNullOrWhiteSpace(type)) 103 | actionFieldInfo.TypeName = type; 104 | 105 | if (!string.IsNullOrWhiteSpace(allowNullable)) 106 | actionFieldInfo.AllowNullable = Convert.ToBoolean(allowNullable); 107 | 108 | if (!string.IsNullOrWhiteSpace(defaultValue)) 109 | actionFieldInfo.DefaultValue = defaultValue; 110 | if (!comment.IsNullOrWhiteSpace()) actionFieldInfo.Comment = comment; 111 | } 112 | } 113 | } 114 | 115 | /// 116 | /// 从SQL语句提取输出字段 117 | /// 118 | /// 119 | /// 120 | protected virtual void SetActionOutputFieldInfosFromSql(string sqlTpl, ActionBuilderInfo actionBuilderInfo) => actionBuilderInfo.ActionOutputInfo.ActionFieldInfos = TSqlParser.GetOutputFieldList(sqlTpl,actionBuilderInfo.ConnectionString).Select(p => new ActionFieldInfo() 121 | { 122 | TypeName = p.CsTypeName, 123 | Name = p.Name, 124 | AllowNullable = p.AllowNullable, 125 | }).ToList(); 126 | 127 | /// 128 | /// 从配置文件获取或重写输入参数 129 | /// 130 | /// 131 | /// 132 | protected virtual void SetActionInputFieldInfosFromConfig(IConfigurationSection sqlApi, ActionBuilderInfo actionBuilderInfo) 133 | { 134 | if (sqlApi.GetSection("Input:Parameter").Exists()) 135 | { 136 | foreach (var par in sqlApi.GetSection("Input:Parameter").GetChildren()) 137 | { 138 | var name = par["Name"]; 139 | var comment = par["Comment"]; 140 | 141 | if (string.IsNullOrWhiteSpace(name)) 142 | continue; 143 | 144 | var type = par["Type"]; 145 | var defaultValue = par["DefaultValue"]; 146 | var allowNullable = par["AllowNullable"]; 147 | var actionFieldInfo = actionBuilderInfo.ActionInputInfo.ActionFieldInfos.FirstOrDefault(p => p.Name == name); 148 | 149 | if (actionFieldInfo == null) 150 | { 151 | actionFieldInfo = new ActionFieldInfo() { Name = name }; 152 | actionBuilderInfo.ActionInputInfo.ActionFieldInfos.Add(actionFieldInfo); 153 | } 154 | 155 | if (!string.IsNullOrWhiteSpace(type)) 156 | actionFieldInfo.TypeName = type; 157 | 158 | if (!string.IsNullOrWhiteSpace(allowNullable)) 159 | actionFieldInfo.AllowNullable = Convert.ToBoolean(allowNullable); 160 | 161 | if (!string.IsNullOrWhiteSpace(defaultValue)) 162 | actionFieldInfo.DefaultValue = defaultValue; 163 | 164 | if (!string.IsNullOrWhiteSpace(comment)) actionFieldInfo.Comment = comment; 165 | } 166 | } 167 | } 168 | 169 | /// 170 | /// 从SQL中提取输入参数 171 | /// 172 | /// 173 | /// 174 | protected virtual void SetActionInputFieldInfosFromSql(string sqlTpl, ActionBuilderInfo actionBuilderInfo) 175 | { 176 | actionBuilderInfo.ActionInputInfo.ActionFieldInfos = TSqlParser.GetParameters(sqlTpl, actionBuilderInfo.ConnectionString).Select(p => new ActionFieldInfo() 177 | { 178 | TypeName = p.CsTypeName, 179 | Name = p.Name?.TrimStart('@') 180 | }).ToList(); 181 | } 182 | 183 | /// 184 | /// 185 | /// 186 | /// 187 | /// 188 | /// 189 | protected virtual ActionBuilderInfo CreateActionBuilderInfo(IConfigurationSection sqlApi, out string sqlTpl) 190 | { 191 | sqlTpl = sqlApi["SqlTpl"]; 192 | var comment = sqlApi["Comment"]; 193 | var httpMethod = sqlApi["HttpMethod"]; 194 | return new ActionBuilderInfo() 195 | { 196 | Name = sqlApi.Key, 197 | HttpMethod = httpMethod, 198 | HttpRoute = sqlApi["HttpRoute"], 199 | ActionInputInfo = new ActionInputInfo() 200 | { 201 | BindFrom = "[FromQuery]" 202 | }, 203 | ActionOutputInfo = new ActionOutputInfo(), 204 | SqlTpl = sqlTpl, 205 | Comment = comment, 206 | HasReturnValue = sqlTpl.IndexOf("select", StringComparison.CurrentCultureIgnoreCase) != -1, 207 | ConnectionString = sqlApi["ConnectionString"] 208 | }; 209 | } 210 | 211 | /// 212 | /// 设置输入参数的绑定方式 213 | /// 214 | /// 215 | /// 216 | protected virtual void SetHttpMethodAndBindFrom(IConfigurationSection sqlApi, ActionBuilderInfo actionBuilderInfo) 217 | { 218 | //[FromQuery] - 从查询字符串中获取值。 219 | //[FromRoute] - 从路由数据中获取值。 220 | //[FromForm] - 从发布的表单域中获取值。 221 | //[FromBody] - 从请求正文中获取值。 222 | //[FromHeader] - 从 HTTP 标头中获取值。 223 | var keys = new Dictionary() 224 | { 225 | { "HttpPost" ,new string[]{ "create", "post", "insert" } }, 226 | { "HttpGet" ,new string[]{ "get","select"} }, 227 | { "HttpPut" ,new string[]{ "put", "update" } }, 228 | { "HttpDelete" ,new string[]{ "delete", "drop","remove" } }, 229 | }; 230 | foreach (var item in keys.Keys) 231 | { 232 | if (keys[item].Any(p => sqlApi.Key.StartsWith(p, StringComparison.CurrentCultureIgnoreCase))) 233 | { 234 | actionBuilderInfo.HttpMethod = item; 235 | if(actionBuilderInfo.HttpRoute.IsNullOrWhiteSpace()) 236 | actionBuilderInfo.HttpRoute = $"[{item}(\"{sqlApi.Key.ToCamelCase()}\")]"; 237 | } 238 | } 239 | switch (actionBuilderInfo.HttpMethod) 240 | { 241 | case "HttpGet": 242 | actionBuilderInfo.ActionInputInfo.BindFrom = "[FromQuery]"; 243 | break; 244 | case "HttpPost": 245 | case "HttpPut": 246 | actionBuilderInfo.ActionInputInfo.BindFrom = "[FromBody]"; 247 | break; 248 | case "HttpDelete": 249 | actionBuilderInfo.ActionInputInfo.BindFrom = "[FromQuery]"; 250 | break; 251 | default: 252 | break; 253 | } 254 | } 255 | 256 | protected StringBuilder CodeSb = new StringBuilder(); 257 | public string Build() 258 | { 259 | CreateCodeBuilderInfo(); 260 | if (CodeBuilderInfo == null) 261 | { 262 | return null; 263 | } 264 | 265 | CodeSb = new StringBuilder(); 266 | NamespacesBuild(); 267 | ControllersBuild(); 268 | return CodeSb.ToString(); 269 | } 270 | 271 | /// 272 | /// 添加命名空间 273 | /// 274 | /// 275 | public virtual void AddNamespace(params string[] namespaces) => CodeBuilderInfo.Namespaces.AddRange(namespaces); 276 | 277 | protected virtual void NamespacesBuild() 278 | { 279 | foreach (var ns in CodeBuilderInfo.Namespaces.Distinct()) 280 | { 281 | CodeSb.AppendFormat("using {0};", ns).AppendLine(); 282 | } 283 | CodeSb.AppendLine(); 284 | } 285 | 286 | /// 287 | /// 构建控制器 288 | /// 289 | protected virtual void ControllersBuild() 290 | { 291 | foreach (var controllerBuilderInfo in CodeBuilderInfo.ControllerBuilderInfos) 292 | { 293 | CodeSb.AppendLine(" [DynamicApiController()]"); 294 | CodeSb.AppendLine(" [ApiController]"); 295 | CodeSb.AppendLine($" [Route(\"{controllerBuilderInfo.Route}\")]"); 296 | if (controllerBuilderInfo.Comment != null) 297 | CodeSb.AppendLine($" [SwaggerTag(\"{controllerBuilderInfo.Comment}\")]"); 298 | CodeSb.AppendLine($" public class {controllerBuilderInfo.Name}Controller : ControllerBase"); 299 | CodeSb.AppendLine(" {"); 300 | CodeSb.AppendLine($" public {controllerBuilderInfo.Name}Controller(ISqlExecutor sqlExecutor, IConfiguration configuration)"); 301 | CodeSb.AppendLine(" {"); 302 | CodeSb.AppendLine(" SqlExecutor = sqlExecutor;"); 303 | CodeSb.AppendLine(" Configuration = configuration;"); 304 | CodeSb.AppendLine(" }"); 305 | CodeSb.AppendLine(" public ISqlExecutor SqlExecutor { get; }"); 306 | CodeSb.AppendLine(" public IConfiguration Configuration { get; }"); 307 | foreach (var actionBuilderInfos in controllerBuilderInfo.ActionBuilderInfos) 308 | { 309 | CodeSb.AppendLine(); 310 | CodeSb.AppendLine($" {actionBuilderInfos.HttpRoute}"); 311 | if (!actionBuilderInfos.Comment.IsNullOrWhiteSpace()) 312 | CodeSb.AppendLine($"[SwaggerOperation(Summary = \"{actionBuilderInfos.Comment}\")]"); 313 | CodeSb.Append(" public async Task<"); 314 | switch (actionBuilderInfos.ActionOutputInfo.ActionOutputType) 315 | { 316 | case ActionOutputTypes.None: 317 | CodeSb.Append("IActionResult"); 318 | break; 319 | case ActionOutputTypes.List: 320 | CodeSb.Append($"IEnumerable<{actionBuilderInfos.Name}Output>"); 321 | break; 322 | default: 323 | CodeSb.Append("IActionResult"); 324 | break; 325 | } 326 | CodeSb.Append($"> {actionBuilderInfos.Name}("); 327 | switch (actionBuilderInfos.ActionInputInfo.ActionInputType) 328 | { 329 | case ActionInputTypes.None: 330 | break; 331 | case ActionInputTypes.Object: 332 | CodeSb.Append($"{actionBuilderInfos.ActionInputInfo.BindFrom}{actionBuilderInfos.Name}Input input"); 333 | break; 334 | default: 335 | break; 336 | } 337 | CodeSb.Append(")").AppendLine(); 338 | CodeSb.AppendLine(" {"); 339 | CodeSb.AppendLine($" var sqlText = Configuration[\"SqlApis:{controllerBuilderInfo.Key}:SqlApi:{actionBuilderInfos.Name}:SqlTpl\"];"); 340 | //SqlApis:AuditLogs:SqlApi:GetAbpAuditLogById:SqlTpl 341 | //Console.WriteLine("SQL:" + Configuration[$"SqlApis:{controllerBuilderInfo.Name}:SqlApi:{actionBuilderInfos.Name}:SqlTpl"]); 342 | if (actionBuilderInfos.HasReturnValue) 343 | { 344 | CodeSb.Append($" return await SqlExecutor.QueryAsync<{actionBuilderInfos.Name}Output>(sqlText{(actionBuilderInfos.ActionInputInfo.ActionInputType == ActionInputTypes.None ? string.Empty : ",input")},connectionString:@\"{actionBuilderInfos.ConnectionString}\");").AppendLine(); 345 | } 346 | else 347 | { 348 | CodeSb.Append($" await SqlExecutor.ExecuteAsync(sqlText{(actionBuilderInfos.ActionInputInfo.ActionInputType == ActionInputTypes.None ? string.Empty : ",input")},connectionString:@\"{actionBuilderInfos.ConnectionString}\");").AppendLine(); 349 | CodeSb.AppendLine("return Ok();"); 350 | } 351 | 352 | CodeSb.AppendLine(" }"); 353 | } 354 | ActionClassBuild(controllerBuilderInfo); 355 | CodeSb.AppendLine(" }"); 356 | CodeSb.AppendLine(); 357 | } 358 | } 359 | 360 | protected virtual string GetParameterTypeName(ActionFieldInfo actionFieldInfo) 361 | { 362 | if (actionFieldInfo.AllowNullable == true && !actionFieldInfo.TypeName.Equals("string", StringComparison.OrdinalIgnoreCase)) 363 | { 364 | return "?"; 365 | } 366 | return null; 367 | } 368 | 369 | /// 370 | /// Action输入输出类构建 371 | /// 372 | protected virtual void ActionClassBuild(ControllerBuilderInfo controllerBuilderInfo) 373 | { 374 | foreach (var actionBuilderInfo in controllerBuilderInfo.ActionBuilderInfos) 375 | { 376 | //构建输入参数类 377 | if (actionBuilderInfo.ActionInputInfo.ActionInputType != ActionInputTypes.None) 378 | { 379 | CodeSb.Append($" public class {actionBuilderInfo.Name}Input").AppendLine(); 380 | CodeSb.AppendLine(" {"); 381 | foreach (var parameter in actionBuilderInfo.ActionInputInfo.ActionFieldInfos) 382 | { 383 | if (!parameter.Comment.IsNullOrWhiteSpace()) 384 | CodeSb.AppendLine($"[SwaggerSchema(\"{parameter.Comment}\")]"); 385 | CodeSb.Append($" public {parameter.TypeName}{GetParameterTypeName(parameter)} {parameter.Name} {{ get; set; }}"); 386 | if (parameter.DefaultValue != null) 387 | { 388 | if (parameter.TypeName == "string") 389 | CodeSb.Append($" = \"{parameter.DefaultValue}\";"); 390 | else 391 | CodeSb.Append($" = {parameter.DefaultValue};"); 392 | } 393 | CodeSb.AppendLine(); 394 | } 395 | 396 | CodeSb.AppendLine(" }"); 397 | } 398 | 399 | //构建输出参数类 400 | if (actionBuilderInfo.ActionOutputInfo.ActionOutputType != ActionOutputTypes.None) 401 | { 402 | CodeSb.Append($" public class {actionBuilderInfo.Name}Output").AppendLine(); 403 | CodeSb.AppendLine(" {"); 404 | foreach (var parameter in actionBuilderInfo.ActionOutputInfo.ActionFieldInfos) 405 | { 406 | if (!parameter.Comment.IsNullOrWhiteSpace()) 407 | CodeSb.AppendLine($"[SwaggerSchema(\"{parameter.Comment}\")]"); 408 | CodeSb.Append($" public {parameter.TypeName}{GetParameterTypeName(parameter)} {parameter.Name.TrimStart('@')} {{ get; set; }}"); 409 | if (parameter.DefaultValue != null) 410 | { 411 | if (parameter.TypeName == "string") 412 | CodeSb.Append($" = \"{parameter.DefaultValue}\";"); 413 | else 414 | CodeSb.Append($" = {parameter.DefaultValue};"); 415 | } 416 | CodeSb.AppendLine(); 417 | } 418 | 419 | CodeSb.AppendLine(" }"); 420 | } 421 | } 422 | } 423 | } 424 | } 425 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/DynamicApis/DynamicApiControllerAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Magicodes.DynamicSqlApi.Core.DynamicApis 6 | { 7 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 8 | public class DynamicApiControllerAttribute : Attribute 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/DynamicApis/GenericTypeControllerFeatureProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.ApplicationParts; 2 | using Microsoft.AspNetCore.Mvc.Controllers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Reflection; 8 | 9 | namespace Magicodes.DynamicSqlApi.Core.DynamicApis 10 | { 11 | public class GenericTypeControllerFeatureProvider : IApplicationFeatureProvider 12 | { 13 | public GenericTypeControllerFeatureProvider(Assembly assembly) 14 | { 15 | Assembly = assembly; 16 | } 17 | 18 | public Assembly Assembly { get; } 19 | 20 | public void PopulateFeature(IEnumerable parts, ControllerFeature feature) 21 | { 22 | var candidates = Assembly.GetExportedTypes().Where(x => x.GetCustomAttributes().Any()); 23 | 24 | foreach (var candidate in candidates) 25 | { 26 | feature.Controllers.Add( 27 | candidate.GetTypeInfo() 28 | 29 | ); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Security.Cryptography; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace Magicodes.DynamicSqlApi.Core.Extensions 9 | { 10 | public static class StringExtensions 11 | { 12 | public static bool IsNullOrEmpty(this string str) 13 | { 14 | return string.IsNullOrEmpty(str); 15 | } 16 | 17 | public static bool IsNullOrWhiteSpace(this string str) 18 | { 19 | return string.IsNullOrWhiteSpace(str); 20 | } 21 | 22 | // 23 | // 摘要: 24 | // Gets a substring of a string from beginning of the string. 25 | // 26 | // 异常: 27 | // T:System.ArgumentNullException: 28 | // Thrown if str is null 29 | // 30 | // T:System.ArgumentException: 31 | // Thrown if len is bigger that string's length 32 | public static string Left(this string str, int len) 33 | { 34 | if (str == null) 35 | { 36 | throw new ArgumentNullException("str"); 37 | } 38 | 39 | if (str.Length < len) 40 | { 41 | throw new ArgumentException("len argument can not be bigger than given string's length!"); 42 | } 43 | 44 | return str.Substring(0, len); 45 | } 46 | 47 | // 48 | // 摘要: 49 | // Converts line endings in the string to System.Environment.NewLine. 50 | public static string NormalizeLineEndings(this string str) 51 | { 52 | return str.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", Environment.NewLine); 53 | } 54 | 55 | // 56 | // 摘要: 57 | // Gets a substring of a string from end of the string. 58 | // 59 | // 异常: 60 | // T:System.ArgumentNullException: 61 | // Thrown if str is null 62 | // 63 | // T:System.ArgumentException: 64 | // Thrown if len is bigger that string's length 65 | public static string Right(this string str, int len) 66 | { 67 | if (str == null) 68 | { 69 | throw new ArgumentNullException("str"); 70 | } 71 | 72 | if (str.Length < len) 73 | { 74 | throw new ArgumentException("len argument can not be bigger than given string's length!"); 75 | } 76 | 77 | return str.Substring(str.Length - len, len); 78 | } 79 | 80 | // 81 | // 摘要: 82 | // Uses string.Split method to split given string by given separator. 83 | public static string[] Split(this string str, string separator) 84 | { 85 | return str.Split(new string[1] { separator }, StringSplitOptions.None); 86 | } 87 | 88 | // 89 | // 摘要: 90 | // Uses string.Split method to split given string by given separator. 91 | public static string[] Split(this string str, string separator, StringSplitOptions options) 92 | { 93 | return str.Split(new string[1] { separator }, options); 94 | } 95 | 96 | // 97 | // 摘要: 98 | // Uses string.Split method to split given string by System.Environment.NewLine. 99 | public static string[] SplitToLines(this string str) 100 | { 101 | return Split(str, Environment.NewLine); 102 | } 103 | 104 | // 105 | // 摘要: 106 | // Uses string.Split method to split given string by System.Environment.NewLine. 107 | public static string[] SplitToLines(this string str, StringSplitOptions options) 108 | { 109 | return Split(str, Environment.NewLine, options); 110 | } 111 | 112 | // 113 | // 摘要: 114 | // Converts PascalCase string to camelCase string. 115 | // 116 | // 参数: 117 | // str: 118 | // String to convert 119 | // 120 | // invariantCulture: 121 | // Invariant culture 122 | // 123 | // 返回结果: 124 | // camelCase of the string 125 | public static string ToCamelCase(this string str, bool invariantCulture = true) 126 | { 127 | if (string.IsNullOrWhiteSpace(str)) 128 | { 129 | return str; 130 | } 131 | 132 | if (str.Length == 1) 133 | { 134 | if (!invariantCulture) 135 | { 136 | return str.ToLower(); 137 | } 138 | 139 | return str.ToLowerInvariant(); 140 | } 141 | 142 | return (invariantCulture ? char.ToLowerInvariant(str[0]) : char.ToLower(str[0])) + str.Substring(1); 143 | } 144 | 145 | // 146 | // 摘要: 147 | // Converts PascalCase string to camelCase string in specified culture. 148 | // 149 | // 参数: 150 | // str: 151 | // String to convert 152 | // 153 | // culture: 154 | // An object that supplies culture-specific casing rules 155 | // 156 | // 返回结果: 157 | // camelCase of the string 158 | public static string ToCamelCase(this string str, CultureInfo culture) 159 | { 160 | if (string.IsNullOrWhiteSpace(str)) 161 | { 162 | return str; 163 | } 164 | 165 | if (str.Length == 1) 166 | { 167 | return str.ToLower(culture); 168 | } 169 | 170 | return char.ToLower(str[0], culture) + str.Substring(1); 171 | } 172 | 173 | // 174 | // 摘要: 175 | // Converts given PascalCase/camelCase string to sentence (by splitting words by 176 | // space). Example: "ThisIsSampleSentence" is converted to "This is a sample sentence". 177 | // 178 | // 参数: 179 | // str: 180 | // String to convert. 181 | // 182 | // invariantCulture: 183 | // Invariant culture 184 | public static string ToSentenceCase(this string str, bool invariantCulture = false) 185 | { 186 | if (string.IsNullOrWhiteSpace(str)) 187 | { 188 | return str; 189 | } 190 | 191 | return Regex.Replace(str, "[a-z][A-Z]", (Match m) => m.Value[0] + " " + (invariantCulture ? char.ToLowerInvariant(m.Value[1]) : char.ToLower(m.Value[1]))); 192 | } 193 | 194 | // 195 | // 摘要: 196 | // Converts given PascalCase/camelCase string to sentence (by splitting words by 197 | // space). Example: "ThisIsSampleSentence" is converted to "This is a sample sentence". 198 | // 199 | // 参数: 200 | // str: 201 | // String to convert. 202 | // 203 | // culture: 204 | // An object that supplies culture-specific casing rules. 205 | public static string ToSentenceCase(this string str, CultureInfo culture) 206 | { 207 | if (string.IsNullOrWhiteSpace(str)) 208 | { 209 | return str; 210 | } 211 | 212 | return Regex.Replace(str, "[a-z][A-Z]", (Match m) => m.Value[0] + " " + char.ToLower(m.Value[1], culture)); 213 | } 214 | 215 | // 216 | // 摘要: 217 | // Converts string to enum value. 218 | // 219 | // 参数: 220 | // value: 221 | // String value to convert 222 | // 223 | // 类型参数: 224 | // T: 225 | // Type of enum 226 | // 227 | // 返回结果: 228 | // Returns enum object 229 | public static T ToEnum(this string value) where T : struct 230 | { 231 | if (value == null) 232 | { 233 | throw new ArgumentNullException("value"); 234 | } 235 | 236 | return (T)Enum.Parse(typeof(T), value); 237 | } 238 | 239 | // 240 | // 摘要: 241 | // Converts string to enum value. 242 | // 243 | // 参数: 244 | // value: 245 | // String value to convert 246 | // 247 | // ignoreCase: 248 | // Ignore case 249 | // 250 | // 类型参数: 251 | // T: 252 | // Type of enum 253 | // 254 | // 返回结果: 255 | // Returns enum object 256 | public static T ToEnum(this string value, bool ignoreCase) where T : struct 257 | { 258 | if (value == null) 259 | { 260 | throw new ArgumentNullException("value"); 261 | } 262 | 263 | return (T)Enum.Parse(typeof(T), value, ignoreCase); 264 | } 265 | 266 | public static string ToMd5(this string str) 267 | { 268 | using (MD5 mD = MD5.Create()) 269 | { 270 | byte[] bytes = Encoding.UTF8.GetBytes(str); 271 | byte[] array = mD.ComputeHash(bytes); 272 | StringBuilder stringBuilder = new StringBuilder(); 273 | byte[] array2 = array; 274 | foreach (byte b in array2) 275 | { 276 | stringBuilder.Append(b.ToString("X2")); 277 | } 278 | 279 | return stringBuilder.ToString(); 280 | } 281 | } 282 | 283 | // 284 | // 摘要: 285 | // Converts camelCase string to PascalCase string. 286 | // 287 | // 参数: 288 | // str: 289 | // String to convert 290 | // 291 | // invariantCulture: 292 | // Invariant culture 293 | // 294 | // 返回结果: 295 | // PascalCase of the string 296 | public static string ToPascalCase(this string str, bool invariantCulture = true) 297 | { 298 | if (string.IsNullOrWhiteSpace(str)) 299 | { 300 | return str; 301 | } 302 | 303 | if (str.Length == 1) 304 | { 305 | if (!invariantCulture) 306 | { 307 | return str.ToUpper(); 308 | } 309 | 310 | return str.ToUpperInvariant(); 311 | } 312 | 313 | return (invariantCulture ? char.ToUpperInvariant(str[0]) : char.ToUpper(str[0])) + str.Substring(1); 314 | } 315 | 316 | // 317 | // 摘要: 318 | // Converts camelCase string to PascalCase string in specified culture. 319 | // 320 | // 参数: 321 | // str: 322 | // String to convert 323 | // 324 | // culture: 325 | // An object that supplies culture-specific casing rules 326 | // 327 | // 返回结果: 328 | // PascalCase of the string 329 | public static string ToPascalCase(this string str, CultureInfo culture) 330 | { 331 | if (string.IsNullOrWhiteSpace(str)) 332 | { 333 | return str; 334 | } 335 | 336 | if (str.Length == 1) 337 | { 338 | return str.ToUpper(culture); 339 | } 340 | 341 | return char.ToUpper(str[0], culture) + str.Substring(1); 342 | } 343 | 344 | // 345 | // 摘要: 346 | // Gets a substring of a string from beginning of the string if it exceeds maximum 347 | // length. 348 | // 349 | // 异常: 350 | // T:System.ArgumentNullException: 351 | // Thrown if str is null 352 | public static string Truncate(this string str, int maxLength) 353 | { 354 | if (str == null) 355 | { 356 | return null; 357 | } 358 | 359 | if (str.Length <= maxLength) 360 | { 361 | return str; 362 | } 363 | 364 | return str.Left(maxLength); 365 | } 366 | 367 | // 368 | // 摘要: 369 | // Gets a substring of a string from beginning of the string if it exceeds maximum 370 | // length. It adds a "..." postfix to end of the string if it's truncated. Returning 371 | // string can not be longer than maxLength. 372 | // 373 | // 异常: 374 | // T:System.ArgumentNullException: 375 | // Thrown if str is null 376 | public static string TruncateWithPostfix(this string str, int maxLength) 377 | { 378 | return str.TruncateWithPostfix(maxLength, "..."); 379 | } 380 | 381 | // 382 | // 摘要: 383 | // Gets a substring of a string from beginning of the string if it exceeds maximum 384 | // length. It adds given postfix to end of the string if it's truncated. Returning 385 | // string can not be longer than maxLength. 386 | // 387 | // 异常: 388 | // T:System.ArgumentNullException: 389 | // Thrown if str is null 390 | public static string TruncateWithPostfix(this string str, int maxLength, string postfix) 391 | { 392 | if (str == null) 393 | { 394 | return null; 395 | } 396 | 397 | if (str == string.Empty || maxLength == 0) 398 | { 399 | return string.Empty; 400 | } 401 | 402 | if (str.Length <= maxLength) 403 | { 404 | return str; 405 | } 406 | 407 | if (maxLength <= postfix.Length) 408 | { 409 | return postfix.Left(maxLength); 410 | } 411 | 412 | return str.Left(maxLength - postfix.Length) + postfix; 413 | } 414 | } 415 | } 416 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/ICodeCompiler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Text; 5 | 6 | namespace Magicodes.DynamicSqlApi.Core 7 | { 8 | /// 9 | /// 动态代码编译器 10 | /// 11 | public interface ICodeCompiler 12 | { 13 | /// 14 | /// 将代码编译成程序集 15 | /// 16 | /// 17 | /// 18 | Assembly CompileCode(string code); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/ISqlExecutor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Magicodes.DynamicSqlApi.Core 8 | { 9 | /// 10 | /// SQL执行器 11 | /// 12 | public interface ISqlExecutor 13 | { 14 | Task ExecuteAsync(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string connectionString = null); 15 | IEnumerable Query(string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null, string connectionString = null); 16 | Task> QueryAsync(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string connectionString = null); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/ITSqlParser.cs: -------------------------------------------------------------------------------- 1 | using Magicodes.DynamicSqlApi.Core.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Magicodes.DynamicSqlApi.Core 7 | { 8 | /// 9 | /// Sql解析器 10 | /// 11 | public interface ITSqlParser 12 | { 13 | /// 14 | /// 获取TSQL执行参数 15 | /// 16 | /// 17 | /// 18 | IEnumerable GetParameters(string sqlText, string connectionString = null); 19 | 20 | /// 21 | /// 获取TSQL输出字段列表 22 | /// 23 | /// 24 | /// 25 | 26 | IEnumerable GetOutputFieldList(string sqlText, string connectionString = null); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/Magicodes.DynamicSqlApi.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1 5 | 6 | 7 | 1701;1702;1591; 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/Models/TSqlOutputFieldInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Magicodes.DynamicSqlApi.Core.Models 2 | { 3 | /// 4 | /// TSQL输出字段信息 5 | /// 6 | public class TSqlOutputFieldInfo 7 | { 8 | /// 9 | /// 名称 10 | /// 11 | public string Name { get; set; } 12 | 13 | /// 14 | /// 是否可为空 15 | /// 16 | public bool AllowNullable { get; set; } 17 | 18 | /// 19 | /// 数据库字段类型 20 | /// 21 | public string SqlTypeName { get; set; } 22 | 23 | /// 24 | /// C#中的参数类型 25 | /// 26 | public string CsTypeName { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/Models/TSqlParameterInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Magicodes.DynamicSqlApi.Core.Models 2 | { 3 | /// 4 | /// TSQL参数信息 5 | /// 6 | public class TSqlParameterInfo 7 | { 8 | /// 9 | /// 参数名称 10 | /// 11 | public string Name { get; set; } 12 | 13 | /// 14 | /// 参数类型 15 | /// 16 | public string SqlTypeName { get; set; } 17 | 18 | /// 19 | /// C#中的参数类型 20 | /// 21 | public string CsTypeName { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Core/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Magicodes.DynamicSqlApi.Core; 2 | using Magicodes.DynamicSqlApi.Core.CodeBuilder; 3 | using Magicodes.DynamicSqlApi.Core.DynamicApis; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.ApplicationParts; 7 | using Microsoft.Extensions.Configuration; 8 | using Microsoft.Extensions.DependencyInjection; 9 | using Microsoft.Extensions.Logging; 10 | using System; 11 | using System.Data; 12 | using System.Data.SqlClient; 13 | 14 | namespace Magicodes.DynamicSqlApi.Core 15 | { 16 | public static class ServiceCollectionExtensions 17 | { 18 | /// 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | public static void AddDynamicSqlApi(this IServiceCollection services, string connectionString, string sqlMapperFileName = "sqlMapper.xml") 25 | where TCodeBuilder : CodeBuilderBase 26 | where TCodeCompiler : class, ICodeCompiler 27 | where TSqlExecutor : class, ISqlExecutor 28 | where TTSqlParser : class, ITSqlParser 29 | { 30 | if (!string.IsNullOrWhiteSpace(connectionString)) 31 | services.AddTransient(p => new SqlConnection(connectionString)); 32 | else 33 | { 34 | throw new ApplicationException("请配置连接字符串!"); 35 | } 36 | services.AddTransient(); 37 | services.AddTransient(); 38 | services.AddTransient(); 39 | services.AddTransient(); 40 | } 41 | 42 | public static void UseDynamicSqlApi(this IApplicationBuilder app) 43 | { 44 | ConfigureAspNetCore(app.ApplicationServices); 45 | } 46 | 47 | public static void ConfigureAspNetCore(IServiceProvider serviceProvider) 48 | { 49 | var partManager = serviceProvider.GetService(); 50 | 51 | var codeBuilder = serviceProvider.GetService(); 52 | var code = codeBuilder.Build(); 53 | if (string.IsNullOrWhiteSpace(code)) return; 54 | 55 | var logger = serviceProvider.GetService(); 56 | if (logger!=null && logger.IsEnabled(LogLevel.Debug)) 57 | logger.LogDebug(code); 58 | 59 | var codeCompiler = serviceProvider.GetService(); 60 | var assembly = codeCompiler.CompileCode(code); 61 | partManager?.FeatureProviders?.Add(new GenericTypeControllerFeatureProvider(assembly)); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.CsScript/CsScriptCodeCompiler.cs: -------------------------------------------------------------------------------- 1 | using CSScriptLib; 2 | using Magicodes.DynamicSqlApi.Core; 3 | using System; 4 | using System.Reflection; 5 | 6 | namespace Magicodes.DynamicSqlApi.CsScript 7 | { 8 | /// 9 | /// CSScript代码编译器 10 | /// 11 | public class CsScriptCodeCompiler : ICodeCompiler 12 | { 13 | /// 14 | /// 使用CSScript Roslyn编译器编译代码,无需安装SDK,但不支持命名空间 15 | /// 16 | /// 17 | /// 18 | public Assembly CompileCode(string code) => CSScript.RoslynEvaluator.CompileCode(code); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.CsScript/Magicodes.DynamicSqlApi.CsScript.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Dapper/DapperSqlExecutor.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using Magicodes.DynamicSqlApi.Core; 3 | using Magicodes.DynamicSqlApi.Core.Extensions; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.Data.SqlClient; 8 | using System.Threading.Tasks; 9 | 10 | namespace Magicodes.DynamicSqlApi.Dapper 11 | { 12 | /// 13 | /// Dapper实现 14 | /// 15 | public class DapperSqlExecutor : ISqlExecutor 16 | { 17 | public DapperSqlExecutor(IDbConnection dbConnection) 18 | { 19 | DbConnection = dbConnection; 20 | } 21 | 22 | public IDbConnection DbConnection { get; } 23 | 24 | public async Task ExecuteAsync(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string connectionString = null) 25 | { 26 | if (!connectionString.IsNullOrWhiteSpace()) 27 | { 28 | return await new SqlConnection(connectionString).ExecuteAsync(sql, param, transaction, commandTimeout, commandType); 29 | } 30 | return await DbConnection.ExecuteAsync(sql, param, transaction, commandTimeout, commandType); 31 | } 32 | 33 | public IEnumerable Query(string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null, string connectionString = null) 34 | { 35 | if (!connectionString.IsNullOrWhiteSpace()) 36 | { 37 | return new SqlConnection(connectionString).Query(sql, param, transaction, buffered, commandTimeout, commandType); 38 | } 39 | return DbConnection.Query(sql, param, transaction, buffered, commandTimeout, commandType); 40 | } 41 | 42 | public async Task> QueryAsync(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string connectionString = null) 43 | { 44 | if (!connectionString.IsNullOrWhiteSpace()) 45 | { 46 | return await new SqlConnection(connectionString).QueryAsync(sql, param, transaction, commandTimeout, commandType); 47 | } 48 | return await DbConnection.QueryAsync(sql, param, transaction, commandTimeout, commandType); 49 | } 50 | 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Dapper/Magicodes.DynamicSqlApi.Dapper.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Sqlserver/GetSqlServerOutputListDto.cs: -------------------------------------------------------------------------------- 1 | namespace Magicodes.DynamicSqlApi.SqlServer 2 | { 3 | public class GetSqlServerOutputListDto 4 | { 5 | /// 6 | /// 指示列是出于浏览信息目的而额外添加的列,该列不会实际显示在结果集中。 7 | /// 8 | public bool is_hidden { get; set; } 9 | 10 | /// 11 | /// 包含列的名称(如果可以确定名称)。 否则,它将包含 NULL。 12 | /// 13 | public string name { get; set; } 14 | 15 | /// 16 | /// 如果列允许 NULL,则包含值 1;如果列不允许 NULL,则包含 0;如果不能确定列是否允许 NULL,则为 1。 17 | /// 18 | public bool is_nullable { get; set; } 19 | 20 | /// 21 | /// 包含为列数据类型指定的名称和参数(例如,length、precision、scale)。 如果数据类型是用户定义的别名类型,则会在此处指定基本系统类型。 如果数据类型是 CLR 用户定义类型,则在此列中返回 NULL。 22 | /// 23 | public string system_type_name { get; set; } 24 | 25 | /// 26 | /// 列的最大长度(字节)。-1 = 的列数据类型为varchar (max) , nvarchar (max) , varbinary (max) ,或者xml。有关文本列, max_length值将是 16,或者设置的值sp_tableoption 'text in row' 。 27 | /// 28 | public short max_length { get; set; } 29 | 30 | /// 31 | /// 如果为基于数值的列,则为该列的精度。 否则,返回 0。 32 | /// 33 | public short precision { get; set; } 34 | 35 | /// 36 | /// 如果基于数值,则为列的小数位数。 否则,返回 0。 37 | /// 38 | public short scale { get; set; } 39 | } 40 | } -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Sqlserver/GetSqlServerParametersOutput.cs: -------------------------------------------------------------------------------- 1 | namespace Magicodes.DynamicSqlApi.SqlServer 2 | { 3 | public class GetSqlServerParametersOutput 4 | { 5 | /// 6 | /// 参数名称 7 | /// 8 | public string name { get; set; } 9 | 10 | /// 11 | /// 参数类型 12 | /// 13 | public string suggested_system_type_name { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Sqlserver/Magicodes.DynamicSqlApi.SqlServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Sqlserver/SqlServerDbTypeMapperHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Text; 5 | 6 | namespace Magicodes.DynamicSqlApi.SqlServer 7 | { 8 | public static class SqlServerDbTypeMapperHelper 9 | { 10 | /// 11 | /// 根据数据库类型获取C#类型 12 | /// 13 | /// 14 | /// 15 | public static string GetCsTypeByDbType(this string dbType) 16 | { 17 | string type; 18 | switch (dbType.Split('(')[0]) 19 | { 20 | case "bit": 21 | type = "bool"; 22 | break; 23 | case "tinyint": 24 | case "smallint": 25 | type = "short"; 26 | break; 27 | case "int": 28 | type = "int"; 29 | break; 30 | case "bigint": 31 | type = "long"; 32 | break; 33 | case "smallmoney": 34 | case "money": 35 | case "float": 36 | case "real": 37 | case "numeric": 38 | type = "decimal"; 39 | break; 40 | case "smalldatetime": 41 | case "datetime": 42 | case "datetime2": 43 | case "datetimeoffset": 44 | type = "DateTime"; 45 | break; 46 | default: 47 | type = "string"; 48 | break; 49 | } 50 | 51 | return type; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Magicodes.DynamicSqlApi.Sqlserver/SqlServerTSqlParser.cs: -------------------------------------------------------------------------------- 1 | using Magicodes.DynamicSqlApi.Core; 2 | using Magicodes.DynamicSqlApi.Core.Models; 3 | using Magicodes.DynamicSqlApi.SqlServer; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.Linq; 8 | 9 | namespace Magicodes.DynamicSqlApi.Sqlserver 10 | { 11 | /// 12 | /// 解析SQL Server语句 13 | /// 14 | public class SqlServerTSqlParser : ITSqlParser 15 | { 16 | public SqlServerTSqlParser(ISqlExecutor sqlExecutor) 17 | { 18 | SqlExecutor = sqlExecutor; 19 | } 20 | 21 | public ISqlExecutor SqlExecutor { get; } 22 | 23 | /// 24 | /// https://docs.microsoft.com/zh-cn/sql/relational-databases/system-stored-procedures/sp-describe-undeclared-parameters-transact-sql?view=sql-server-ver15 25 | /// 26 | /// 27 | /// 28 | public IEnumerable GetParameters(string sqlText, string connectionString = null) 29 | { 30 | return SqlExecutor.Query("sp_describe_undeclared_parameters", new 31 | { 32 | tsql = sqlText 33 | }, commandType: CommandType.StoredProcedure, connectionString: connectionString).Select(p => new TSqlParameterInfo() 34 | { 35 | CsTypeName = p.suggested_system_type_name.GetCsTypeByDbType(), 36 | Name = p.name 37 | }); 38 | } 39 | 40 | 41 | /// 42 | /// https://docs.microsoft.com/zh-cn/sql/relational-databases/system-stored-procedures/sp-describe-first-result-set-transact-sql?view=sql-server-ver15 43 | /// 44 | /// 45 | /// 46 | public IEnumerable GetOutputFieldList(string sqlText, string connectionString = null) 47 | { 48 | return SqlExecutor.Query("sp_describe_first_result_set", new 49 | { 50 | tsql = sqlText, 51 | @params = string.Empty, 52 | browse_information_mode = 1 53 | }, commandType: CommandType.StoredProcedure, connectionString: connectionString) 54 | //不输出隐藏列 55 | .Where(p => !p.is_hidden) 56 | .Select(p => new TSqlOutputFieldInfo() 57 | { 58 | CsTypeName = p.system_type_name.GetCsTypeByDbType(), 59 | Name = p.name, 60 | AllowNullable = p.is_nullable, 61 | SqlTypeName = p.system_type_name 62 | }); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Web2_2/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace Web2_2 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .ConfigureAppConfiguration((hostingContext, config) => 23 | { 24 | var env = hostingContext.HostingEnvironment; 25 | //根据环境变量加载不同的JSON配置 26 | config.AddJsonFile("appsettings.json", true, true) 27 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", 28 | true, true); 29 | //从环境变量添加配置 30 | config.AddEnvironmentVariables(); 31 | config.AddXmlFile("sqlMapper.xml", true, false); 32 | }) 33 | .UseStartup(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Web2_2/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:25011/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "Web2_2": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "launchUrl": "swagger", 22 | "applicationUrl": "http://localhost:5000/", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/Web2_2/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Magicodes.DynamicSqlApi.All; 6 | using Magicodes.DynamicSqlApi.Core; 7 | using Magicodes.SwaggerUI; 8 | using Microsoft.AspNetCore.Builder; 9 | using Microsoft.AspNetCore.Hosting; 10 | using Microsoft.AspNetCore.Http; 11 | using Microsoft.AspNetCore.Internal; 12 | using Microsoft.AspNetCore.Mvc; 13 | using Microsoft.Extensions.Configuration; 14 | using Microsoft.Extensions.DependencyInjection; 15 | 16 | namespace Web2_2 17 | { 18 | public class Startup 19 | { 20 | public Startup(IConfiguration configuration) 21 | { 22 | Configuration = configuration; 23 | } 24 | 25 | public IConfiguration Configuration { get; } 26 | 27 | public void ConfigureServices(IServiceCollection services) 28 | { 29 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 30 | 31 | services.AddAllDynamicSqlApi(Configuration["ConnectionStrings:Default"]); 32 | 33 | //添加自定义API文档生成(支持文档配置) 34 | services.AddCustomSwaggerGen(Configuration); 35 | } 36 | 37 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 38 | { 39 | if (env.IsDevelopment()) 40 | { 41 | app.UseDeveloperExceptionPage(); 42 | } 43 | app.UseDynamicSqlApi(); 44 | 45 | app.UseMvc(routes => routes.MapRoute( 46 | "default", 47 | "{controller=Home}/{action=Index}/{id?}")); 48 | 49 | //启用自定义API文档(支持文档配置) 50 | app.UseCustomSwaggerUI(Configuration); 51 | 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Web2_2/Web2_2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | InProcess 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Always 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Web2_2/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Web2_2/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "Default": "Server=(localdb)\\MSSQLLocalDB; Database=Admin_V1; Trusted_Connection=True;" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Warning" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "SwaggerDoc": { 12 | "IsEnabled": "true", 13 | //将枚举值以字符串显示 14 | "DescribeAllEnumsAsStrings": false, 15 | "SwaggerDocInfos": [ 16 | { 17 | "IsEnabled": "true", 18 | "Title": "APP API文档", 19 | "Version": "v1", 20 | //"GroupName": "", 21 | "Description": "", 22 | "Contact": { 23 | "Name": "心莱科技", 24 | "Email": "xinlai@xin-lai.com" 25 | } 26 | //"GroupUrlPrefix": "api/app1/" 27 | } 28 | ], 29 | "UseFullNameForSchemaId": "false" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Web2_2/sqlMapper.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | SELECT TOP 1 * FROM [dbo].[AbpAuditLogs] 14 | WHERE [Id] = @Id 15 | 16 | 17 | 18 | 19 | 20 | 21 | SELECT TOP (1000) * 22 | FROM [dbo].[AbpUsers] 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Web3_1/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | // For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 8 | 9 | namespace Web3_1 10 | { 11 | public class HomeController : Controller 12 | { 13 | // GET: // 14 | public IActionResult Index() 15 | { 16 | return View(); 17 | } 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/Web3_1/Program.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xin-lai/Magicodes.DynamicSqlApi/7d5c4890a2aa704aa36a7ee7b579bf4fe1c919d3/src/Web3_1/Program.cs -------------------------------------------------------------------------------- /src/Web3_1/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:28404/", 8 | "sslPort": 0 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "Web3_1": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "swagger", 24 | "applicationUrl": "http://localhost:5000/", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Web3_1/Startup.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xin-lai/Magicodes.DynamicSqlApi/7d5c4890a2aa704aa36a7ee7b579bf4fe1c919d3/src/Web3_1/Startup.cs -------------------------------------------------------------------------------- /src/Web3_1/Web3_1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | PreserveNewest 15 | true 16 | PreserveNewest 17 | 18 | 19 | PreserveNewest 20 | true 21 | PreserveNewest 22 | 23 | 24 | 25 | 26 | 27 | Always 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Web3_1/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Web3_1/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "Default": "Server=(localdb)\\MSSQLLocalDB; Database=Admin_V1; Trusted_Connection=True;" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Warning" 8 | } 9 | }, 10 | "AllowedHosts": "*" 11 | } 12 | -------------------------------------------------------------------------------- /src/Web3_1/sqlMapper.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | SELECT TOP 1 * FROM [dbo].[AbpAuditLogs] 14 | WHERE [Id] = @Id 15 | 16 | 17 | 18 | 19 | 20 | 21 | SELECT TOP (1000) * 22 | FROM [dbo].[AbpUsers] 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Web6/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.CodeAnalysis; 3 | using Swashbuckle.AspNetCore.Annotations; 4 | 5 | namespace Web6.Controllers 6 | { 7 | [ApiController] 8 | [Route("[controller]")] 9 | public class WeatherForecastController : ControllerBase 10 | { 11 | private static readonly string[] Summaries = new[] 12 | { 13 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 14 | }; 15 | 16 | private readonly ILogger _logger; 17 | 18 | public WeatherForecastController(ILogger logger) 19 | { 20 | _logger = logger; 21 | } 22 | 23 | [HttpGet(Name = "GetWeatherForecast")] 24 | [SwaggerOperation(Summary = "Creates a new product",Tags = new string[] {"Students"})] 25 | public IEnumerable Get() 26 | { 27 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 28 | { 29 | Date = DateTime.Now.AddDays(index), 30 | TemperatureC = Random.Shared.Next(-20, 55), 31 | Summary = Summaries[Random.Shared.Next(Summaries.Length)] 32 | }) 33 | .ToArray(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Web6/Data/AppDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Web6.Data.Models; 3 | 4 | namespace Web6.Data 5 | { 6 | public class AppDbContext : DbContext 7 | { 8 | 9 | public AppDbContext(DbContextOptions options) : base(options) 10 | { 11 | 12 | } 13 | 14 | 15 | public DbSet Classes { get; set; } 16 | 17 | public DbSet Grades { get; set; } 18 | 19 | public DbSet Students { get; set; } 20 | 21 | public DbSet Majors { get; set; } 22 | 23 | 24 | protected override void OnModelCreating(ModelBuilder modelBuilder) 25 | { 26 | base.OnModelCreating(modelBuilder); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Web6/Data/Models/ClassInfo.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Schema; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.Diagnostics; 4 | using System.Xml.Linq; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace Web6.Data.Models 8 | { 9 | public class ClassInfo 10 | { 11 | public int Id { get; set; } 12 | /// 13 | ///班级名称 14 | /// 15 | [Required(ErrorMessage = "名称不能为空")] 16 | [Comment("名称")] 17 | public string Name { get; set; } 18 | 19 | /// 20 | /// 所属专业id 21 | /// 22 | [Required(ErrorMessage = "所属专业不能为空")] 23 | [Comment("专业Id")] 24 | public int MajorId { get; set; } 25 | 26 | /// 27 | /// 专业信息 28 | /// 29 | [ForeignKey("MajorId")] 30 | public virtual MajorInfo Major { get; set; } 31 | 32 | /// 33 | /// 所属年级id 34 | /// 35 | public int GradeId { get; set; } 36 | 37 | /// 38 | /// 开班日期 39 | /// 40 | [Display(Name = "开班日期")] 41 | public DateTime StartDate { get; set; } 42 | 43 | /// 44 | /// 年级信息 45 | /// 46 | [ForeignKey("GradeId")] 47 | public virtual GradeInfo Grade { get; set; } 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Web6/Data/Models/GradeInfo.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Web6.Data.Models 4 | { 5 | public class GradeInfo 6 | { 7 | public int Id { get; set; } 8 | 9 | /// 10 | /// 年级名称 11 | /// 12 | [Required(ErrorMessage = "名称不能为空")] 13 | public string Name { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Web6/Data/Models/MajorInfo.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Infrastructure; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace Web6.Data.Models 6 | { 7 | public class MajorInfo 8 | { 9 | public int Id { get; set; } 10 | /// 11 | ///名称 12 | /// 13 | [Required(ErrorMessage = "名称不能为空")] 14 | public string Name { get; set; } 15 | 16 | /// 17 | /// 学年制 18 | /// 19 | [Required(ErrorMessage = "学年制不能为空")] 20 | public double YearSystem { get; set; } 21 | 22 | /// 23 | /// 编码 24 | /// 25 | public string Code { get; set; } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Web6/Data/Models/StudentInfo.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Web6.Data.Models 4 | { 5 | public class StudentInfo 6 | { 7 | public int Id { get; set; } 8 | 9 | [Required(ErrorMessage = "学生姓名不能为空")] 10 | [MaxLength(ValidationConsts.StringDefaultMaxLangth, ErrorMessage = "名称字数超出最大限制,请修改!")] 11 | public string Name { get; set; } 12 | 13 | /// 14 | ///身份证 15 | /// 16 | [MaxLength(ValidationConsts.IdCardMaxLength, ErrorMessage = "身份证字数超出最大限制,请修改!")] 17 | public string IdCard { get; set; } 18 | 19 | /// 20 | /// 学籍号 21 | /// 22 | [MaxLength(ValidationConsts.StudentCodeMaxLength, ErrorMessage = "学籍号字数超出最大限制,请修改!")] 23 | public string StudentCode { get; set; } 24 | 25 | /// 26 | ///手机号码 27 | /// 28 | [MaxLength(ValidationConsts.PhoneNumberMaxLength, ErrorMessage = "手机号码字数超出最大限制,请修改!")] 29 | public string Phone { get; set; } 30 | 31 | /// 32 | ///民族 33 | /// 34 | [MaxLength(ValidationConsts.StringDefaultMaxLangth, ErrorMessage = "民族字数超出最大限制,请修改!")] 35 | public string Nation { get; set; } 36 | 37 | /// 38 | /// 监护人 39 | /// 40 | [MaxLength(ValidationConsts.StringDefaultMaxLangth, ErrorMessage = "监护字数超出最大限制,请修改!")] 41 | public string Guardian { get; set; } 42 | 43 | /// 44 | /// 监护人电话 45 | /// 46 | [MaxLength(ValidationConsts.PhoneNumberMaxLength, ErrorMessage = "监护人电话字数超出最大限制,请修改!")] 47 | public string GuardianPhone { get; set; } 48 | 49 | /// 50 | /// 家庭地址 51 | /// 52 | [MaxLength(ValidationConsts.AddressMaxLength, ErrorMessage = "家庭地址字数超出最大限制,请修改!")] 53 | public string Address { get; set; } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Web6/Data/Models/ValidationConsts.cs: -------------------------------------------------------------------------------- 1 | namespace Web6.Data.Models 2 | { 3 | internal class ValidationConsts 4 | { 5 | /// 6 | /// 短字符默认长度 7 | /// 8 | public const int ShortStringMaxLangth = 10; 9 | 10 | /// 11 | /// 字符串默认长度 12 | /// 13 | public const int StringDefaultMaxLangth = 50; 14 | 15 | /// 16 | /// Url最大长度 17 | /// 18 | public const int UrlMaxLength = 225; 19 | 20 | /// 21 | /// 名称最大长度 22 | /// 23 | public const int NameMaxLength = 64; 24 | 25 | /// 26 | /// 邮箱地址最大长度 27 | /// 28 | public const int EmailAddressMaxLength = 256; 29 | 30 | /// 31 | /// 手机号码最大长度 32 | /// 33 | public const int PhoneNumberMaxLength = 15; 34 | 35 | /// 36 | /// 备注最大长度 37 | /// 38 | public const int RemarkMaxLength = 500; 39 | 40 | /// 41 | /// 描述最大长度 42 | /// 43 | public const int DescriptionMaxLength = 2000; 44 | 45 | /// 46 | /// 用户名最大长度 47 | /// 48 | public const int UserNameMaxLength = 256; 49 | 50 | /// 51 | /// 金额最大值 52 | /// 53 | public const int AmountMaxinum = 1000000; 54 | 55 | /// 56 | /// 金额最小值 57 | /// 58 | public const int AmountMininum = 0; 59 | 60 | /// 61 | /// 路径最大长度 62 | /// 63 | public const int PathMaxLength = 256; 64 | 65 | /// 66 | /// 身份证最大长度 67 | /// 68 | public const int IdCardMaxLength = 18; 69 | 70 | /// 71 | /// 学籍号最大长度 72 | /// 73 | public const int StudentCodeMaxLength = 25; 74 | 75 | /// 76 | /// 学号最大长度 77 | /// 78 | public const int StuNubMaxLength = 25; 79 | 80 | /// 81 | /// 住址最大长度 82 | /// 83 | public const int AddressMaxLength = 256; 84 | 85 | /// 86 | /// 代码、编号最大长度 87 | /// 88 | public const int CodeMaxLength = 32; 89 | 90 | /// 91 | /// 更长的代码、编号最大长度 92 | /// 93 | public const int LongCodeMaxLength = 50; 94 | 95 | /// 96 | /// IP地址最大长度 97 | /// 98 | public const int IpAddressMaxLength = 64; 99 | 100 | /// 101 | /// 异常最大长度 102 | /// 103 | public const int ExceptionMaxLength = 2000; 104 | 105 | 106 | /// 107 | /// 项目日志名称最大长度 108 | /// 109 | public const int LogProjectNameMaxLangth = 64; 110 | 111 | /// 112 | /// 原因最大长度 113 | /// 114 | public const int ReasonLength = 30; 115 | 116 | /// 117 | /// 密码最大长度 118 | /// 119 | public const int PasswordLength = 30; 120 | 121 | /// 122 | /// 身份证正则表达式 123 | /// 124 | public const string IdcardVerify = @"^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$"; 125 | } 126 | } -------------------------------------------------------------------------------- /src/Web6/Migrations/20221205144119_Init.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using Web6.Data; 9 | 10 | #nullable disable 11 | 12 | namespace Web6.Migrations 13 | { 14 | [DbContext(typeof(AppDbContext))] 15 | [Migration("20221205144119_Init")] 16 | partial class Init 17 | { 18 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 19 | { 20 | #pragma warning disable 612, 618 21 | modelBuilder 22 | .HasAnnotation("ProductVersion", "6.0.8") 23 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 24 | 25 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); 26 | 27 | modelBuilder.Entity("Web6.Data.Models.ClassInfo", b => 28 | { 29 | b.Property("Id") 30 | .ValueGeneratedOnAdd() 31 | .HasColumnType("int"); 32 | 33 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 34 | 35 | b.Property("GradeId") 36 | .HasColumnType("int"); 37 | 38 | b.Property("MajorId") 39 | .HasColumnType("int") 40 | .HasComment("专业Id"); 41 | 42 | b.Property("Name") 43 | .IsRequired() 44 | .HasColumnType("nvarchar(max)") 45 | .HasComment("名称"); 46 | 47 | b.Property("StartDate") 48 | .HasColumnType("datetime2"); 49 | 50 | b.HasKey("Id"); 51 | 52 | b.HasIndex("GradeId"); 53 | 54 | b.HasIndex("MajorId"); 55 | 56 | b.ToTable("Classes"); 57 | }); 58 | 59 | modelBuilder.Entity("Web6.Data.Models.GradeInfo", b => 60 | { 61 | b.Property("Id") 62 | .ValueGeneratedOnAdd() 63 | .HasColumnType("int"); 64 | 65 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 66 | 67 | b.Property("Name") 68 | .IsRequired() 69 | .HasColumnType("nvarchar(max)"); 70 | 71 | b.HasKey("Id"); 72 | 73 | b.ToTable("Grades"); 74 | }); 75 | 76 | modelBuilder.Entity("Web6.Data.Models.MajorInfo", b => 77 | { 78 | b.Property("Id") 79 | .ValueGeneratedOnAdd() 80 | .HasColumnType("int"); 81 | 82 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 83 | 84 | b.Property("Code") 85 | .HasColumnType("nvarchar(max)"); 86 | 87 | b.Property("Name") 88 | .IsRequired() 89 | .HasColumnType("nvarchar(max)"); 90 | 91 | b.Property("YearSystem") 92 | .HasColumnType("float"); 93 | 94 | b.HasKey("Id"); 95 | 96 | b.ToTable("Majors"); 97 | }); 98 | 99 | modelBuilder.Entity("Web6.Data.Models.StudentInfo", b => 100 | { 101 | b.Property("Id") 102 | .ValueGeneratedOnAdd() 103 | .HasColumnType("int"); 104 | 105 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 106 | 107 | b.Property("Address") 108 | .HasMaxLength(256) 109 | .HasColumnType("nvarchar(256)"); 110 | 111 | b.Property("Guardian") 112 | .HasMaxLength(50) 113 | .HasColumnType("nvarchar(50)"); 114 | 115 | b.Property("GuardianPhone") 116 | .HasMaxLength(15) 117 | .HasColumnType("nvarchar(15)"); 118 | 119 | b.Property("IdCard") 120 | .HasMaxLength(18) 121 | .HasColumnType("nvarchar(18)"); 122 | 123 | b.Property("Name") 124 | .IsRequired() 125 | .HasMaxLength(50) 126 | .HasColumnType("nvarchar(50)"); 127 | 128 | b.Property("Nation") 129 | .HasMaxLength(50) 130 | .HasColumnType("nvarchar(50)"); 131 | 132 | b.Property("Phone") 133 | .HasMaxLength(15) 134 | .HasColumnType("nvarchar(15)"); 135 | 136 | b.Property("StudentCode") 137 | .HasMaxLength(25) 138 | .HasColumnType("nvarchar(25)"); 139 | 140 | b.HasKey("Id"); 141 | 142 | b.ToTable("Students"); 143 | }); 144 | 145 | modelBuilder.Entity("Web6.Data.Models.ClassInfo", b => 146 | { 147 | b.HasOne("Web6.Data.Models.GradeInfo", "Grade") 148 | .WithMany() 149 | .HasForeignKey("GradeId") 150 | .OnDelete(DeleteBehavior.Cascade) 151 | .IsRequired(); 152 | 153 | b.HasOne("Web6.Data.Models.MajorInfo", "Major") 154 | .WithMany() 155 | .HasForeignKey("MajorId") 156 | .OnDelete(DeleteBehavior.Cascade) 157 | .IsRequired(); 158 | 159 | b.Navigation("Grade"); 160 | 161 | b.Navigation("Major"); 162 | }); 163 | #pragma warning restore 612, 618 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/Web6/Migrations/20221205144119_Init.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | #nullable disable 5 | 6 | namespace Web6.Migrations 7 | { 8 | public partial class Init : Migration 9 | { 10 | protected override void Up(MigrationBuilder migrationBuilder) 11 | { 12 | migrationBuilder.CreateTable( 13 | name: "Grades", 14 | columns: table => new 15 | { 16 | Id = table.Column(type: "int", nullable: false) 17 | .Annotation("SqlServer:Identity", "1, 1"), 18 | Name = table.Column(type: "nvarchar(max)", nullable: false) 19 | }, 20 | constraints: table => 21 | { 22 | table.PrimaryKey("PK_Grades", x => x.Id); 23 | }); 24 | 25 | migrationBuilder.CreateTable( 26 | name: "Majors", 27 | columns: table => new 28 | { 29 | Id = table.Column(type: "int", nullable: false) 30 | .Annotation("SqlServer:Identity", "1, 1"), 31 | Name = table.Column(type: "nvarchar(max)", nullable: false), 32 | YearSystem = table.Column(type: "float", nullable: false), 33 | Code = table.Column(type: "nvarchar(max)", nullable: true) 34 | }, 35 | constraints: table => 36 | { 37 | table.PrimaryKey("PK_Majors", x => x.Id); 38 | }); 39 | 40 | migrationBuilder.CreateTable( 41 | name: "Students", 42 | columns: table => new 43 | { 44 | Id = table.Column(type: "int", nullable: false) 45 | .Annotation("SqlServer:Identity", "1, 1"), 46 | Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), 47 | IdCard = table.Column(type: "nvarchar(18)", maxLength: 18, nullable: true), 48 | StudentCode = table.Column(type: "nvarchar(25)", maxLength: 25, nullable: true), 49 | Phone = table.Column(type: "nvarchar(15)", maxLength: 15, nullable: true), 50 | Nation = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), 51 | Guardian = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), 52 | GuardianPhone = table.Column(type: "nvarchar(15)", maxLength: 15, nullable: true), 53 | Address = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true) 54 | }, 55 | constraints: table => 56 | { 57 | table.PrimaryKey("PK_Students", x => x.Id); 58 | }); 59 | 60 | migrationBuilder.CreateTable( 61 | name: "Classes", 62 | columns: table => new 63 | { 64 | Id = table.Column(type: "int", nullable: false) 65 | .Annotation("SqlServer:Identity", "1, 1"), 66 | Name = table.Column(type: "nvarchar(max)", nullable: false, comment: "名称"), 67 | MajorId = table.Column(type: "int", nullable: false, comment: "专业Id"), 68 | GradeId = table.Column(type: "int", nullable: false), 69 | StartDate = table.Column(type: "datetime2", nullable: false) 70 | }, 71 | constraints: table => 72 | { 73 | table.PrimaryKey("PK_Classes", x => x.Id); 74 | table.ForeignKey( 75 | name: "FK_Classes_Grades_GradeId", 76 | column: x => x.GradeId, 77 | principalTable: "Grades", 78 | principalColumn: "Id", 79 | onDelete: ReferentialAction.Cascade); 80 | table.ForeignKey( 81 | name: "FK_Classes_Majors_MajorId", 82 | column: x => x.MajorId, 83 | principalTable: "Majors", 84 | principalColumn: "Id", 85 | onDelete: ReferentialAction.Cascade); 86 | }); 87 | 88 | migrationBuilder.CreateIndex( 89 | name: "IX_Classes_GradeId", 90 | table: "Classes", 91 | column: "GradeId"); 92 | 93 | migrationBuilder.CreateIndex( 94 | name: "IX_Classes_MajorId", 95 | table: "Classes", 96 | column: "MajorId"); 97 | } 98 | 99 | protected override void Down(MigrationBuilder migrationBuilder) 100 | { 101 | migrationBuilder.DropTable( 102 | name: "Classes"); 103 | 104 | migrationBuilder.DropTable( 105 | name: "Students"); 106 | 107 | migrationBuilder.DropTable( 108 | name: "Grades"); 109 | 110 | migrationBuilder.DropTable( 111 | name: "Majors"); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Web6/Migrations/AppDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | using Web6.Data; 8 | 9 | #nullable disable 10 | 11 | namespace Web6.Migrations 12 | { 13 | [DbContext(typeof(AppDbContext))] 14 | partial class AppDbContextModelSnapshot : ModelSnapshot 15 | { 16 | protected override void BuildModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "6.0.8") 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 22 | 23 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); 24 | 25 | modelBuilder.Entity("Web6.Data.Models.ClassInfo", b => 26 | { 27 | b.Property("Id") 28 | .ValueGeneratedOnAdd() 29 | .HasColumnType("int"); 30 | 31 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 32 | 33 | b.Property("GradeId") 34 | .HasColumnType("int"); 35 | 36 | b.Property("MajorId") 37 | .HasColumnType("int") 38 | .HasComment("专业Id"); 39 | 40 | b.Property("Name") 41 | .IsRequired() 42 | .HasColumnType("nvarchar(max)") 43 | .HasComment("名称"); 44 | 45 | b.Property("StartDate") 46 | .HasColumnType("datetime2"); 47 | 48 | b.HasKey("Id"); 49 | 50 | b.HasIndex("GradeId"); 51 | 52 | b.HasIndex("MajorId"); 53 | 54 | b.ToTable("Classes"); 55 | }); 56 | 57 | modelBuilder.Entity("Web6.Data.Models.GradeInfo", b => 58 | { 59 | b.Property("Id") 60 | .ValueGeneratedOnAdd() 61 | .HasColumnType("int"); 62 | 63 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 64 | 65 | b.Property("Name") 66 | .IsRequired() 67 | .HasColumnType("nvarchar(max)"); 68 | 69 | b.HasKey("Id"); 70 | 71 | b.ToTable("Grades"); 72 | }); 73 | 74 | modelBuilder.Entity("Web6.Data.Models.MajorInfo", b => 75 | { 76 | b.Property("Id") 77 | .ValueGeneratedOnAdd() 78 | .HasColumnType("int"); 79 | 80 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 81 | 82 | b.Property("Code") 83 | .HasColumnType("nvarchar(max)"); 84 | 85 | b.Property("Name") 86 | .IsRequired() 87 | .HasColumnType("nvarchar(max)"); 88 | 89 | b.Property("YearSystem") 90 | .HasColumnType("float"); 91 | 92 | b.HasKey("Id"); 93 | 94 | b.ToTable("Majors"); 95 | }); 96 | 97 | modelBuilder.Entity("Web6.Data.Models.StudentInfo", b => 98 | { 99 | b.Property("Id") 100 | .ValueGeneratedOnAdd() 101 | .HasColumnType("int"); 102 | 103 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 104 | 105 | b.Property("Address") 106 | .HasMaxLength(256) 107 | .HasColumnType("nvarchar(256)"); 108 | 109 | b.Property("Guardian") 110 | .HasMaxLength(50) 111 | .HasColumnType("nvarchar(50)"); 112 | 113 | b.Property("GuardianPhone") 114 | .HasMaxLength(15) 115 | .HasColumnType("nvarchar(15)"); 116 | 117 | b.Property("IdCard") 118 | .HasMaxLength(18) 119 | .HasColumnType("nvarchar(18)"); 120 | 121 | b.Property("Name") 122 | .IsRequired() 123 | .HasMaxLength(50) 124 | .HasColumnType("nvarchar(50)"); 125 | 126 | b.Property("Nation") 127 | .HasMaxLength(50) 128 | .HasColumnType("nvarchar(50)"); 129 | 130 | b.Property("Phone") 131 | .HasMaxLength(15) 132 | .HasColumnType("nvarchar(15)"); 133 | 134 | b.Property("StudentCode") 135 | .HasMaxLength(25) 136 | .HasColumnType("nvarchar(25)"); 137 | 138 | b.HasKey("Id"); 139 | 140 | b.ToTable("Students"); 141 | }); 142 | 143 | modelBuilder.Entity("Web6.Data.Models.ClassInfo", b => 144 | { 145 | b.HasOne("Web6.Data.Models.GradeInfo", "Grade") 146 | .WithMany() 147 | .HasForeignKey("GradeId") 148 | .OnDelete(DeleteBehavior.Cascade) 149 | .IsRequired(); 150 | 151 | b.HasOne("Web6.Data.Models.MajorInfo", "Major") 152 | .WithMany() 153 | .HasForeignKey("MajorId") 154 | .OnDelete(DeleteBehavior.Cascade) 155 | .IsRequired(); 156 | 157 | b.Navigation("Grade"); 158 | 159 | b.Navigation("Major"); 160 | }); 161 | #pragma warning restore 612, 618 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/Web6/Program.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xin-lai/Magicodes.DynamicSqlApi/7d5c4890a2aa704aa36a7ee7b579bf4fe1c919d3/src/Web6/Program.cs -------------------------------------------------------------------------------- /src/Web6/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:57677", 8 | "sslPort": 0 9 | } 10 | }, 11 | "profiles": { 12 | "Web6": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:5263", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "IIS Express": { 23 | "commandName": "IISExpress", 24 | "launchBrowser": true, 25 | "launchUrl": "swagger", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Web6/WeatherForecast.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xin-lai/Magicodes.DynamicSqlApi/7d5c4890a2aa704aa36a7ee7b579bf4fe1c919d3/src/Web6/WeatherForecast.cs -------------------------------------------------------------------------------- /src/Web6/Web6.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Always 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/Web6/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=test;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Debug", 8 | "Microsoft.AspNetCore": "Warning" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Web6/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/Web6/sqlMapper.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | SELECT TOP 1 * FROM [dbo].[Students] 14 | WHERE [Id] = @Id 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | INSERT INTO [dbo].[Students] 23 | ([Name],[IdCard],[StudentCode],[Phone],[Nation],[Guardian],[GuardianPhone],[Address]) 24 | VALUES 25 | (@Name,@IdCard,@StudentCode,@Phone,@Nation,@Guardian,@GuardianPhone,@Address) 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | select top (select (@PageSize)) * 34 | from (select row_number() over(order by id) as rownumber,* 35 | from [dbo].[Students]) temp_row 36 | where rownumber>(@SkipCount) 37 | 38 | 39 | 40 | 41 | 42 | 43 | SELECT TOP (1000) * 44 | FROM [dbo].[Classes] 45 | 46 | 47 | 48 | 49 | 50 | 51 | SELECT TOP (@PageSize) * 52 | FROM [dbo].[Devices] 53 | 54 | 55 | 56 | --------------------------------------------------------------------------------