├── nugeticon.png
├── Sixnet.Database.SqlServer
├── sixnet.snk
├── Sixnet.Database.SqlServer.csproj
├── SqlServerBulkInsertOptions.cs
├── SqlServerManager.cs
├── SqlServerFieldFormatter.cs
├── SqlServerProvider.cs
└── SqlServerDataCommandResolver.cs
├── README.md
├── LICENSE
├── Sixnet.Database.SqlServer.sln
├── Sixnet.Database.SqlServer.nuspec
└── .gitignore
/nugeticon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/six-net/Sixnet.Database.SqlServer/HEAD/nugeticon.png
--------------------------------------------------------------------------------
/Sixnet.Database.SqlServer/sixnet.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/six-net/Sixnet.Database.SqlServer/HEAD/Sixnet.Database.SqlServer/sixnet.snk
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sixnet.Database.SqlServer
2 |
3 | Provides access to SQL Server databases based on the Sixnet development framework
4 |
5 | # Reporting issues and bugs
6 |
7 | If you have any questions or Suggestions, you can report to us via email,to the lidingbin@live.com, and we will reply to you as soon as possible, or you can contact [DingBin Li](https://github.com/lidingbin) via GitHub
8 |
9 |
--------------------------------------------------------------------------------
/Sixnet.Database.SqlServer/Sixnet.Database.SqlServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | true
6 | sixnet.snk
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 EZNEW.NET
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 |
--------------------------------------------------------------------------------
/Sixnet.Database.SqlServer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32825.248
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sixnet.Database.SqlServer", "Sixnet.Database.SqlServer\Sixnet.Database.SqlServer.csproj", "{64248439-C198-41FA-BAD7-955FA9A6BF26}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {64248439-C198-41FA-BAD7-955FA9A6BF26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {64248439-C198-41FA-BAD7-955FA9A6BF26}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {64248439-C198-41FA-BAD7-955FA9A6BF26}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {64248439-C198-41FA-BAD7-955FA9A6BF26}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {AB6DAF42-3235-4CEA-A23D-D8C0D2D65512}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/Sixnet.Database.SqlServer.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Sixnet.Database.SqlServer
5 | $version$
6 |
7 | DingBin.Li
8 | DingBin.Li
9 | false
10 | MIT
11 | https://github.com/sixnet-net
12 | images\nugeticon.png
13 | Provides access to SQL Serever databases based on the Sixnet development framework
14 | Copyright © DingBin.Li
15 | .NET,Sixnet,SQL Serever
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Sixnet.Database.SqlServer/SqlServerBulkInsertOptions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Data.SqlClient;
3 | using Sixnet.Development.Data.Database;
4 |
5 | namespace Sixnet.Database.SqlServer
6 | {
7 | ///
8 | /// SqlServer bulk insert options
9 | ///
10 | public class SqlServerBulkInsertOptions : IBulkInsertionOptions
11 | {
12 | ///
13 | // Returns a collection of System.Data.SqlClient.SqlBulkCopyColumnMapping items.
14 | // Column mappings define the relationships between columns in the data source and
15 | // columns in the destination.
16 | ///
17 | public List ColumnMappings { get; set; }
18 |
19 | ///
20 | /// Number of seconds for the operation to complete before it times out.
21 | /// The default is 30 seconds. A value of 0 indicates no limit,the bulk copy will wait indefinitely.
22 | ///
23 | public int BulkCopyTimeout { get; set; } = 30;
24 |
25 | ///
26 | /// Number of rows in each batch. At the end of each batch, the rows in the batch are sent to the server.
27 | /// By default, SqlBulkCopy will process the operation in a single batch
28 | ///
29 | public int BatchSize { get; set; }
30 |
31 | ///
32 | /// Indicates whether use transaction
33 | /// Default is false
34 | ///
35 | public bool UseTransaction { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Sixnet.Database.SqlServer/SqlServerManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Data.SqlClient;
4 | using Sixnet.Development.Data;
5 | using Sixnet.Development.Data.Command;
6 | using Sixnet.Development.Data.Database;
7 | using Sixnet.Logging;
8 |
9 | namespace Sixnet.Database.SqlServer
10 | {
11 | ///
12 | /// Defines sqlserver manager
13 | ///
14 | internal static class SqlServerManager
15 | {
16 | #region Fields
17 |
18 | ///
19 | /// Gets current database server type
20 | ///
21 | internal const DatabaseServerType CurrentDatabaseServerType = DatabaseServerType.SQLServer;
22 |
23 | ///
24 | /// Key word prefix
25 | ///
26 | internal const string KeywordPrefix = "[";
27 |
28 | ///
29 | /// Key word suffix
30 | ///
31 | internal const string KeywordSuffix = "]";
32 |
33 | ///
34 | /// Default data command resolver
35 | ///
36 | static readonly SqlServerDataCommandResolver DefaultDataCommandResolver = new SqlServerDataCommandResolver();
37 |
38 | #endregion
39 |
40 | #region Get database connection
41 |
42 | ///
43 | /// Get sqlserver database connection
44 | ///
45 | /// Database server
46 | /// Return database connection
47 | internal static IDbConnection GetConnection(DatabaseServer server)
48 | {
49 | return DataManager.GetDatabaseConnection(server) ?? new SqlConnection(server.ConnectionString);
50 | }
51 |
52 | #endregion
53 |
54 | #region Wrap keyword
55 |
56 | ///
57 | /// Wrap keyword by the KeywordPrefix and the KeywordSuffix
58 | ///
59 | /// Original value
60 | ///
61 | internal static string WrapKeyword(string originalValue)
62 | {
63 | return $"{KeywordPrefix}{originalValue}{KeywordSuffix}";
64 | }
65 |
66 | #endregion
67 |
68 | #region Command resolver
69 |
70 | ///
71 | /// Get command resolver
72 | ///
73 | /// Return a command resolver
74 | internal static SqlServerDataCommandResolver GetCommandResolver()
75 | {
76 | return DefaultDataCommandResolver;
77 | }
78 |
79 | #endregion
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Sixnet.Database.SqlServer/SqlServerFieldFormatter.cs:
--------------------------------------------------------------------------------
1 | using Sixnet.Development.Data.Field.Formatting;
2 | using Sixnet.Exceptions;
3 |
4 | namespace Sixnet.Database.SqlServer
5 | {
6 | ///
7 | /// Default field formatter for sqlserver
8 | ///
9 | public class SqlServerFieldFormatter : IFieldFormatter
10 | {
11 | public string Format(FieldFormatContext context)
12 | {
13 | var formatOption = context.FormatOption;
14 | var formatedFieldName = context.FieldName;
15 | formatedFieldName = formatOption.Name switch
16 | {
17 | FieldFormatterNames.CHARLENGTH => $"LEN({formatedFieldName})",
18 | FieldFormatterNames.COUNT => $"COUNT({formatedFieldName})",
19 | FieldFormatterNames.SUM => $"SUM({formatedFieldName})",
20 | FieldFormatterNames.MAX => $"MAX({formatedFieldName})",
21 | FieldFormatterNames.MIN => $"MIN({formatedFieldName})",
22 | FieldFormatterNames.AVG => $"AVG({formatedFieldName})",
23 | FieldFormatterNames.JSON_VALUE => $"JSON_VALUE({formatedFieldName},{formatOption.Parameter})",
24 | FieldFormatterNames.JSON_OBJECT => $"JSON_QUERY({formatedFieldName},{formatOption.Parameter})",
25 | FieldFormatterNames.AND => $"({formatedFieldName}&{formatOption.Parameter})",
26 | FieldFormatterNames.OR => $"({formatedFieldName}|{formatOption.Parameter})",
27 | FieldFormatterNames.XOR => $"({formatedFieldName}^{formatOption.Parameter})",
28 | FieldFormatterNames.NOT => $"(~{formatedFieldName})",
29 | FieldFormatterNames.ADD => $"({formatedFieldName}+{formatOption.Parameter})",
30 | FieldFormatterNames.SUBTRACT => $"({formatedFieldName}-{formatOption.Parameter})",
31 | FieldFormatterNames.MULTIPLY => $"({formatedFieldName}*{formatOption.Parameter})",
32 | FieldFormatterNames.DIVIDE => $"({formatedFieldName}/{formatOption.Parameter})",
33 | FieldFormatterNames.MODULO => $"({formatedFieldName}%{formatOption.Parameter})",
34 | FieldFormatterNames.LEFT_SHIFT => $"({formatedFieldName}<<{formatOption.Parameter})",
35 | FieldFormatterNames.RIGHT_SHIFT => $"({formatedFieldName}>>{formatOption.Parameter})",
36 | FieldFormatterNames.TRIM => $"TRIM({formatedFieldName})",
37 | FieldFormatterNames.STRING_CONCAT => $"({formatedFieldName}+{formatOption.Parameter})",
38 | _ => throw new SixnetException($"{SqlServerManager.CurrentDatabaseServerType} does not support field formatter: {formatOption.Name}"),
39 | };
40 | return formatedFieldName;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sixnet.Database.SqlServer/SqlServerProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Data;
3 | using System.Data.SqlClient;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Sixnet.Development.Data.Command;
7 | using Sixnet.Development.Data.Dapper;
8 | using Sixnet.Development.Data.Database;
9 | using Sixnet.Exceptions;
10 |
11 | namespace Sixnet.Database.SqlServer
12 | {
13 | ///
14 | /// Imeplements database provider for sqlserver
15 | ///
16 | public class SqlServerProvider : BaseDatabaseProvider
17 | {
18 | #region Constructor
19 |
20 | public SqlServerProvider()
21 | {
22 | queryDatabaseTablesScript = "SELECT [NAME] AS [TableName] FROM SYSOBJECTS WHERE XTYPE='U' AND CATEGORY=0";
23 | }
24 |
25 | #endregion
26 |
27 | #region Connection
28 |
29 | ///
30 | /// Get database connection
31 | ///
32 | /// Database server
33 | ///
34 | public override IDbConnection GetDbConnection(DatabaseServer server)
35 | {
36 | return SqlServerManager.GetConnection(server);
37 | }
38 |
39 | #endregion
40 |
41 | #region Data command resolver
42 |
43 | ///
44 | /// Get data command resolver
45 | ///
46 | ///
47 | protected override IDataCommandResolver GetDataCommandResolver()
48 | {
49 | return SqlServerManager.GetCommandResolver();
50 | }
51 |
52 | #endregion
53 |
54 | #region Parameter
55 |
56 | ///
57 | /// Convert data command parametes
58 | ///
59 | /// Data command parameters
60 | ///
61 | protected override DynamicParameters ConvertDataCommandParameters(DataCommandParameters parameters)
62 | {
63 | return parameters?.ConvertToDynamicParameters(SqlServerManager.CurrentDatabaseServerType);
64 | }
65 |
66 | #endregion
67 |
68 | #region Bulk
69 |
70 | ///
71 | /// Bulk insert datas
72 | ///
73 | /// Database bulk insert command
74 | public override async Task BulkInsertAsync(DatabaseBulkInsertCommand command)
75 | {
76 | SixnetException.ThrowIf(command?.DataTable == null, "Not set datatable");
77 | var bulkInsertOptions = command.BulkInsertionOptions;
78 | var dbConnection = command.Connection.DbConnection as SqlConnection;
79 | using (var sqlServerBulkCopy = new SqlBulkCopy(dbConnection, SqlBulkCopyOptions.Default, command.Connection.Transaction.DbTransaction as SqlTransaction))
80 | {
81 | if (bulkInsertOptions is SqlServerBulkInsertOptions sqlServerBulkInsertOptions)
82 | {
83 | if (!sqlServerBulkInsertOptions.ColumnMappings.IsNullOrEmpty())
84 | {
85 | sqlServerBulkInsertOptions.ColumnMappings.ForEach(c =>
86 | {
87 | sqlServerBulkCopy.ColumnMappings.Add(c);
88 | });
89 | }
90 | if (sqlServerBulkInsertOptions.BulkCopyTimeout > 0)
91 | {
92 | sqlServerBulkCopy.BulkCopyTimeout = sqlServerBulkInsertOptions.BulkCopyTimeout;
93 | }
94 | if (sqlServerBulkInsertOptions.BatchSize > 0)
95 | {
96 | sqlServerBulkCopy.BatchSize = sqlServerBulkInsertOptions.BatchSize;
97 | }
98 | }
99 | if (sqlServerBulkCopy.ColumnMappings.Count < 1)
100 | {
101 | BuildColumnMapping(sqlServerBulkCopy, command.DataTable);
102 | }
103 | sqlServerBulkCopy.DestinationTableName = command.DataTable.TableName;
104 | await sqlServerBulkCopy.WriteToServerAsync(command.DataTable).ConfigureAwait(false);
105 | sqlServerBulkCopy.Close();
106 | }
107 | }
108 |
109 | ///
110 | /// Bulk insert datas
111 | ///
112 | /// Database bulk insert command
113 | public override void BulkInsert(DatabaseBulkInsertCommand command)
114 | {
115 | SixnetException.ThrowIf(command?.DataTable == null, "Not set datatable");
116 | var bulkInsertOptions = command.BulkInsertionOptions;
117 | var dbConnection = command.Connection.DbConnection as SqlConnection;
118 | using (var sqlServerBulkCopy = new SqlBulkCopy(dbConnection, SqlBulkCopyOptions.Default, command.Connection.Transaction.DbTransaction as SqlTransaction))
119 | {
120 | if (bulkInsertOptions is SqlServerBulkInsertOptions sqlServerBulkInsertOptions)
121 | {
122 | if (!sqlServerBulkInsertOptions.ColumnMappings.IsNullOrEmpty())
123 | {
124 | sqlServerBulkInsertOptions.ColumnMappings.ForEach(c =>
125 | {
126 | sqlServerBulkCopy.ColumnMappings.Add(c);
127 | });
128 | }
129 | if (sqlServerBulkInsertOptions.BulkCopyTimeout > 0)
130 | {
131 | sqlServerBulkCopy.BulkCopyTimeout = sqlServerBulkInsertOptions.BulkCopyTimeout;
132 | }
133 | if (sqlServerBulkInsertOptions.BatchSize > 0)
134 | {
135 | sqlServerBulkCopy.BatchSize = sqlServerBulkInsertOptions.BatchSize;
136 | }
137 | }
138 | if (sqlServerBulkCopy.ColumnMappings.Count < 1)
139 | {
140 | BuildColumnMapping(sqlServerBulkCopy, command.DataTable);
141 | }
142 | sqlServerBulkCopy.DestinationTableName = command.DataTable.TableName;
143 | sqlServerBulkCopy.WriteToServer(command.DataTable);
144 | sqlServerBulkCopy.Close();
145 | }
146 | }
147 |
148 | ///
149 | /// Build column mapping
150 | ///
151 | ///
152 | ///
153 | static void BuildColumnMapping(SqlBulkCopy sqlBulkCopy, DataTable dataTable)
154 | {
155 | foreach (DataColumn column in dataTable.Columns)
156 | {
157 | sqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping()
158 | {
159 | SourceColumn = column.ColumnName,
160 | DestinationColumn = column.ColumnName
161 | });
162 | }
163 | }
164 |
165 | #endregion
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/.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 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 |
56 | # StyleCop
57 | StyleCopReport.xml
58 |
59 | # Files built by Visual Studio
60 | *_i.c
61 | *_p.c
62 | *_i.h
63 | *.ilk
64 | *.meta
65 | *.obj
66 | *.iobj
67 | *.pch
68 | *.pdb
69 | *.ipdb
70 | *.pgc
71 | *.pgd
72 | *.rsp
73 | *.sbr
74 | *.tlb
75 | *.tli
76 | *.tlh
77 | *.tmp
78 | *.tmp_proj
79 | *.log
80 | *.vspscc
81 | *.vssscc
82 | .builds
83 | *.pidb
84 | *.svclog
85 | *.scc
86 |
87 | # Chutzpah Test files
88 | _Chutzpah*
89 |
90 | # Visual C++ cache files
91 | ipch/
92 | *.aps
93 | *.ncb
94 | *.opendb
95 | *.opensdf
96 | *.sdf
97 | *.cachefile
98 | *.VC.db
99 | *.VC.VC.opendb
100 |
101 | # Visual Studio profiler
102 | *.psess
103 | *.vsp
104 | *.vspx
105 | *.sap
106 |
107 | # Visual Studio Trace Files
108 | *.e2e
109 |
110 | # TFS 2012 Local Workspace
111 | $tf/
112 |
113 | # Guidance Automation Toolkit
114 | *.gpState
115 |
116 | # ReSharper is a .NET coding add-in
117 | _ReSharper*/
118 | *.[Rr]e[Ss]harper
119 | *.DotSettings.user
120 |
121 | # JustCode is a .NET coding add-in
122 | .JustCode
123 |
124 | # TeamCity is a build add-in
125 | _TeamCity*
126 |
127 | # DotCover is a Code Coverage Tool
128 | *.dotCover
129 |
130 | # AxoCover is a Code Coverage Tool
131 | .axoCover/*
132 | !.axoCover/settings.json
133 |
134 | # Visual Studio code coverage results
135 | *.coverage
136 | *.coveragexml
137 |
138 | # NCrunch
139 | _NCrunch_*
140 | .*crunch*.local.xml
141 | nCrunchTemp_*
142 |
143 | # MightyMoose
144 | *.mm.*
145 | AutoTest.Net/
146 |
147 | # Web workbench (sass)
148 | .sass-cache/
149 |
150 | # Installshield output folder
151 | [Ee]xpress/
152 |
153 | # DocProject is a documentation generator add-in
154 | DocProject/buildhelp/
155 | DocProject/Help/*.HxT
156 | DocProject/Help/*.HxC
157 | DocProject/Help/*.hhc
158 | DocProject/Help/*.hhk
159 | DocProject/Help/*.hhp
160 | DocProject/Help/Html2
161 | DocProject/Help/html
162 |
163 | # Click-Once directory
164 | publish/
165 |
166 | # Publish Web Output
167 | *.[Pp]ublish.xml
168 | *.azurePubxml
169 | # Note: Comment the next line if you want to checkin your web deploy settings,
170 | # but database connection strings (with potential passwords) will be unencrypted
171 | *.pubxml
172 | *.publishproj
173 |
174 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
175 | # checkin your Azure Web App publish settings, but sensitive information contained
176 | # in these scripts will be unencrypted
177 | PublishScripts/
178 |
179 | # NuGet Packages
180 | *.nupkg
181 | # The packages folder can be ignored because of Package Restore
182 | **/[Pp]ackages/*
183 | # except build/, which is used as an MSBuild target.
184 | !**/[Pp]ackages/build/
185 | # Uncomment if necessary however generally it will be regenerated when needed
186 | #!**/[Pp]ackages/repositories.config
187 | # NuGet v3's project.json files produces more ignorable files
188 | *.nuget.props
189 | *.nuget.targets
190 |
191 | # Microsoft Azure Build Output
192 | csx/
193 | *.build.csdef
194 |
195 | # Microsoft Azure Emulator
196 | ecf/
197 | rcf/
198 |
199 | # Windows Store app package directories and files
200 | AppPackages/
201 | BundleArtifacts/
202 | Package.StoreAssociation.xml
203 | _pkginfo.txt
204 | *.appx
205 |
206 | # Visual Studio cache files
207 | # files ending in .cache can be ignored
208 | *.[Cc]ache
209 | # but keep track of directories ending in .cache
210 | !*.[Cc]ache/
211 |
212 | # Others
213 | ClientBin/
214 | ~$*
215 | *~
216 | *.dbmdl
217 | *.dbproj.schemaview
218 | *.jfm
219 | *.pfx
220 | *.publishsettings
221 | orleans.codegen.cs
222 |
223 | # Including strong name files can present a security risk
224 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
225 | #*.snk
226 |
227 | # Since there are multiple workflows, uncomment next line to ignore bower_components
228 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
229 | #bower_components/
230 |
231 | # RIA/Silverlight projects
232 | Generated_Code/
233 |
234 | # Backup & report files from converting an old project file
235 | # to a newer Visual Studio version. Backup files are not needed,
236 | # because we have git ;-)
237 | _UpgradeReport_Files/
238 | Backup*/
239 | UpgradeLog*.XML
240 | UpgradeLog*.htm
241 | ServiceFabricBackup/
242 | *.rptproj.bak
243 |
244 | # SQL Server files
245 | *.mdf
246 | *.ldf
247 | *.ndf
248 |
249 | # Business Intelligence projects
250 | *.rdl.data
251 | *.bim.layout
252 | *.bim_*.settings
253 | *.rptproj.rsuser
254 |
255 | # Microsoft Fakes
256 | FakesAssemblies/
257 |
258 | # GhostDoc plugin setting file
259 | *.GhostDoc.xml
260 |
261 | # Node.js Tools for Visual Studio
262 | .ntvs_analysis.dat
263 | node_modules/
264 |
265 | # Visual Studio 6 build log
266 | *.plg
267 |
268 | # Visual Studio 6 workspace options file
269 | *.opt
270 |
271 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
272 | *.vbw
273 |
274 | # Visual Studio LightSwitch build output
275 | **/*.HTMLClient/GeneratedArtifacts
276 | **/*.DesktopClient/GeneratedArtifacts
277 | **/*.DesktopClient/ModelManifest.xml
278 | **/*.Server/GeneratedArtifacts
279 | **/*.Server/ModelManifest.xml
280 | _Pvt_Extensions
281 |
282 | # Paket dependency manager
283 | .paket/paket.exe
284 | paket-files/
285 |
286 | # FAKE - F# Make
287 | .fake/
288 |
289 | # JetBrains Rider
290 | .idea/
291 | *.sln.iml
292 |
293 | # CodeRush
294 | .cr/
295 |
296 | # Python Tools for Visual Studio (PTVS)
297 | __pycache__/
298 | *.pyc
299 |
300 | # Cake - Uncomment if you are using it
301 | # tools/**
302 | # !tools/packages.config
303 |
304 | # Tabs Studio
305 | *.tss
306 |
307 | # Telerik's JustMock configuration file
308 | *.jmconfig
309 |
310 | # BizTalk build output
311 | *.btp.cs
312 | *.btm.cs
313 | *.odx.cs
314 | *.xsd.cs
315 |
316 | # OpenCover UI analysis results
317 | OpenCover/
318 |
319 | # Azure Stream Analytics local run output
320 | ASALocalRun/
321 |
322 | # MSBuild Binary and Structured Log
323 | *.binlog
324 |
325 | # NVidia Nsight GPU debugger configuration file
326 | *.nvuser
327 |
328 | # MFractors (Xamarin productivity tool) working folder
329 | .mfractor/
--------------------------------------------------------------------------------
/Sixnet.Database.SqlServer/SqlServerDataCommandResolver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data;
4 | using System.Linq;
5 | using System.Text;
6 | using Sixnet.Development.Data;
7 | using Sixnet.Development.Data.Command;
8 | using Sixnet.Development.Data.Database;
9 | using Sixnet.Development.Data.Field;
10 | using Sixnet.Development.Entity;
11 | using Sixnet.Development.Queryable;
12 | using Sixnet.Exceptions;
13 |
14 | namespace Sixnet.Database.SqlServer
15 | {
16 | ///
17 | /// Defines data command resolver for sqlserver
18 | ///
19 | internal class SqlServerDataCommandResolver : BaseDataCommandResolver
20 | {
21 | #region Constructor
22 |
23 | public SqlServerDataCommandResolver()
24 | {
25 | DatabaseServerType = DatabaseServerType.SQLServer;
26 | DefaultFieldFormatter = new SqlServerFieldFormatter();
27 | WrapKeywordFunc = SqlServerManager.WrapKeyword;
28 | RecursiveKeyword = "WITH";
29 | DbTypeDefaultValues = new Dictionary()
30 | {
31 | { DbType.Byte, "0" },
32 | { DbType.SByte, "0" },
33 | { DbType.Int16, "0" },
34 | { DbType.UInt16, "0" },
35 | { DbType.Int32, "0" },
36 | { DbType.UInt32, "0" },
37 | { DbType.Int64, "0" },
38 | { DbType.UInt64, "0" },
39 | { DbType.Single, "0" },
40 | { DbType.Double, "0" },
41 | { DbType.Decimal, "0" },
42 | { DbType.Boolean, "0" },
43 | { DbType.String, "''" },
44 | { DbType.StringFixedLength, "''" },
45 | { DbType.Guid, "NEWID()" },
46 | { DbType.DateTime, "GETDATE()" },
47 | { DbType.DateTime2, "SYSDATETIME()" },
48 | { DbType.DateTimeOffset, "SYSDATETIMEOFFSET()" },
49 | { DbType.Time, "SYSUTCDATETIME()" }
50 | };
51 | }
52 |
53 | #endregion
54 |
55 | #region Get query statement
56 |
57 | ///
58 | /// Get query statement
59 | ///
60 | /// Command resolve context
61 | /// Queryable translation result
62 | /// Queryable location
63 | ///
64 | protected override DatabaseQueryStatement GenerateQueryStatementCore(DataCommandResolveContext context, QueryableTranslationResult translationResult, QueryableLocation location)
65 | {
66 | var queryable = translationResult.GetOriginalQueryable();
67 | string sqlStatement;
68 | IEnumerable outputFields = null;
69 | switch (queryable.ExecutionMode)
70 | {
71 | case QueryableExecutionMode.Script:
72 | sqlStatement = translationResult.GetCondition();
73 | break;
74 | case QueryableExecutionMode.Regular:
75 | default:
76 | // table pet name
77 | var tablePetName = context.GetTablePetName(queryable, queryable.GetModelType());
78 | //combine
79 | var combine = translationResult.GetCombine();
80 | var hasCombine = !string.IsNullOrWhiteSpace(combine);
81 | //having
82 | var having = translationResult.GetHavingCondition();
83 | //group
84 | var group = translationResult.GetGroup();
85 | //pre script output
86 | var targetScript = translationResult.GetPreOutputStatement();
87 |
88 | if (string.IsNullOrWhiteSpace(targetScript))
89 | {
90 | //target
91 | var targetStatement = GetFromTargetStatement(context, queryable, location, tablePetName);
92 | outputFields = targetStatement.OutputFields;
93 | //condition
94 | var condition = translationResult.GetCondition(ConditionStartKeyword);
95 | //join
96 | var join = translationResult.GetJoin();
97 | //target statement
98 | targetScript = $"{targetStatement.Script}{join}{condition}{group}{having}";
99 | }
100 | else
101 | {
102 | targetScript = $"{targetScript}{group}{having}";
103 | outputFields = translationResult.GetPreOutputFields();
104 | }
105 |
106 | // output fields
107 | if (outputFields.IsNullOrEmpty() || !queryable.SelectedFields.IsNullOrEmpty())
108 | {
109 | outputFields = DataManager.GetQueryableFields(DatabaseServerType, queryable.GetModelType(), queryable, context.IsRootQueryable(queryable));
110 | }
111 | var outputFieldString = FormatFieldsString(context, queryable, location, FieldLocation.Output, outputFields);
112 |
113 | //sort
114 | var hasOffset = queryable.SkipCount > 0;
115 | var hasTakeNum = queryable.TakeCount > 0;
116 | var sort = translationResult.GetSort();
117 | var hasSort = !string.IsNullOrWhiteSpace(sort);
118 | if (hasTakeNum && hasOffset && !hasSort)
119 | {
120 | sort = GetDefaultSort(context, translationResult, queryable, outputFields, tablePetName);
121 | hasSort = !string.IsNullOrWhiteSpace(sort);
122 | }
123 |
124 | //limit
125 | var limit = GetLimitString(queryable.SkipCount, queryable.TakeCount, hasSort);
126 | var hasLimit = !string.IsNullOrWhiteSpace(limit);
127 | var useTop = hasLimit && limit.Contains("TOP");
128 |
129 | //statement
130 | sqlStatement = $"SELECT{(useTop ? limit : "")}{GetDistinctString(queryable)} {outputFieldString} FROM {targetScript}{sort}{(!useTop && hasLimit ? limit : "")}";
131 | //pre script
132 | var preScript = GetPreScript(context, location);
133 | switch (queryable.OutputType)
134 | {
135 | case QueryableOutputType.Count:
136 | sqlStatement = hasCombine
137 | ? $"{preScript}SELECT COUNT(1) FROM (({sqlStatement}){combine}){TablePetNameKeyword}{tablePetName}"
138 | : $"{preScript}SELECT COUNT(1) FROM ({sqlStatement}){TablePetNameKeyword}{tablePetName}";
139 | break;
140 | case QueryableOutputType.Predicate:
141 | sqlStatement = hasCombine
142 | ? $"{preScript}SELECT 1 WHEN EXISTS(({sqlStatement}){combine})"
143 | : $"{preScript}SELECT 1 WHEN EXISTS({sqlStatement})";
144 | break;
145 | default:
146 | sqlStatement = hasCombine
147 | ? $"{preScript}({sqlStatement}){combine}"
148 | : $"{preScript}{sqlStatement}";
149 | break;
150 | }
151 | break;
152 | }
153 |
154 | //parameters
155 | var parameters = context.GetParameters();
156 |
157 | //log script
158 | if (location == QueryableLocation.Top)
159 | {
160 | LogScript(sqlStatement, parameters);
161 | }
162 | return DatabaseQueryStatement.Create(sqlStatement, parameters, outputFields);
163 | }
164 |
165 | #endregion
166 |
167 | #region Get insert statement
168 |
169 | ///
170 | /// Get insert statement
171 | ///
172 | /// Command resolve context
173 | ///
174 | protected override List GenerateInsertStatements(DataCommandResolveContext context)
175 | {
176 | var command = context.DataCommandExecutionContext.Command;
177 | var dataCommandExecutionContext = context.DataCommandExecutionContext;
178 | var entityType = dataCommandExecutionContext.Command.GetEntityType();
179 | var fields = DataManager.GetInsertableFields(DatabaseServerType, entityType);
180 | var fieldCount = fields.GetCount();
181 | var insertFields = new List(fieldCount);
182 | var insertValues = new List(fieldCount);
183 | EntityField autoIncrementField = null;
184 | EntityField splitField = null;
185 | dynamic splitValue = default;
186 |
187 | foreach (var field in fields)
188 | {
189 | if (field.InRole(FieldRole.Increment))
190 | {
191 | autoIncrementField ??= field;
192 | if (!autoIncrementField.InRole(FieldRole.PrimaryKey) && field.InRole(FieldRole.PrimaryKey)) // get first primary key field
193 | {
194 | autoIncrementField = field;
195 | }
196 | continue;
197 | }
198 | // fields
199 | insertFields.Add(WrapKeywordFunc(field.FieldName));
200 | // values
201 | var insertValue = command.FieldsAssignment.GetNewValue(field.PropertyName);
202 | insertValues.Add(FormatInsertValueField(context, command.Queryable, insertValue));
203 |
204 | // split value
205 | if (field.InRole(FieldRole.SplitValue))
206 | {
207 | splitValue = insertValue;
208 | splitField = field;
209 | }
210 | }
211 |
212 | ThrowHelper.ThrowNotSupportIf(autoIncrementField != null && splitField != null, $"Not support auto increment field for split table:{entityType.Name}");
213 |
214 | if (splitField != null)
215 | {
216 | dataCommandExecutionContext.SetSplitValues(new List(1) { splitValue });
217 | }
218 | var tableNames = dataCommandExecutionContext.GetTableNames();
219 |
220 | ThrowHelper.ThrowInvalidOperationIf(tableNames.IsNullOrEmpty(), $"Get table name failed for {entityType.Name}");
221 | ThrowHelper.ThrowInvalidOperationIf(tableNames.Count > 1 && autoIncrementField != null, $"Not support auto increment field for multiple tables");
222 |
223 | var statementBuilder = new StringBuilder();
224 | var incrScripts = new List();
225 | var scriptTemplate = $"INSERT INTO {{0}} ({string.Join(",", insertFields)}) VALUES ({string.Join(",", insertValues)});";
226 | foreach (var tableName in tableNames)
227 | {
228 | statementBuilder.AppendLine(string.Format(scriptTemplate, WrapKeywordFunc(tableName)));
229 | }
230 | if (autoIncrementField != null)
231 | {
232 | var incrField = $"{command.Id}";
233 | var incrParameter = FormatParameterName(incrField);
234 | statementBuilder.AppendLine($"DECLARE {incrParameter} BIGINT;SET {incrParameter} = SCOPE_IDENTITY();");
235 | incrScripts.Add($"{incrParameter} {ColumnPetNameKeyword} {incrField}");
236 | }
237 | return new List()
238 | {
239 | new DatabaseExecutionStatement()
240 | {
241 | Script = statementBuilder.ToString(),
242 | ScriptType = GetCommandType(command),
243 | MustAffectData = command.Options?.MustAffectData ?? false,
244 | Parameters = context.GetParameters(),
245 | IncrScript = string.Join(",", incrScripts)
246 | }
247 | };
248 | }
249 |
250 | #endregion
251 |
252 | #region Get update statement
253 |
254 | ///
255 | /// Get update statement
256 | ///
257 | /// Command resolve context
258 | ///
259 | protected override List GenerateUpdateStatements(DataCommandResolveContext context)
260 | {
261 | var command = context.DataCommandExecutionContext.Command;
262 | SixnetException.ThrowIf(command?.FieldsAssignment?.NewValues.IsNullOrEmpty() ?? true, "No set update field");
263 |
264 | #region translate
265 |
266 | var translationResult = Translate(context);
267 | var preScripts = context.GetPreScripts();
268 |
269 | #endregion
270 |
271 | #region script
272 |
273 | var dataCommandExecutionContext = context.DataCommandExecutionContext;
274 | var entityType = dataCommandExecutionContext.Command.GetEntityType();
275 |
276 | var tableNames = dataCommandExecutionContext.GetTableNames(command);
277 | ThrowHelper.ThrowInvalidOperationIf(tableNames.IsNullOrEmpty(), $"Get table name failed for {entityType.Name}");
278 |
279 | var tablePetName = command.Queryable == null ? context.GetNewTablePetName() : context.GetDefaultTablePetName(command.Queryable);
280 | var newValues = command.FieldsAssignment.NewValues;
281 | var updateSetArray = new List();
282 | foreach (var newValueItem in newValues)
283 | {
284 | var newValue = newValueItem.Value;
285 | var propertyName = newValueItem.Key;
286 | var updateField = DataManager.GetField(dataCommandExecutionContext.Server.ServerType, command.GetEntityType(), PropertyField.Create(propertyName)) as PropertyField;
287 |
288 | ThrowHelper.ThrowFrameworkErrorIf(updateField == null, $"Not found field:{propertyName}");
289 |
290 | var fieldFormattedName = WrapKeywordFunc(updateField.FieldName);
291 | var newValueExpression = FormatUpdateValueField(context, command, newValue);
292 | updateSetArray.Add($"{tablePetName}.{fieldFormattedName}={newValueExpression}");
293 | }
294 |
295 | // parameters
296 | var parameters = ConvertParameter(command.ScriptParameters) ?? new DataCommandParameters();
297 | parameters.Union(context.GetParameters());
298 |
299 | // statement
300 | var scriptType = GetCommandType(command);
301 | string scriptTemplate;
302 | if (preScripts.IsNullOrEmpty())
303 | {
304 | var condition = translationResult?.GetCondition(ConditionStartKeyword);
305 | var join = translationResult?.GetJoin();
306 | scriptTemplate = $"UPDATE {tablePetName} SET {string.Join(",", updateSetArray)} FROM {{0}}{TablePetNameKeyword}{tablePetName}{join}{condition};";
307 | var statementBuilder = new StringBuilder();
308 | foreach (var tableName in tableNames)
309 | {
310 | statementBuilder.AppendLine(string.Format(scriptTemplate, WrapKeywordFunc(tableName)));
311 | }
312 | return new List(1)
313 | {
314 | new DatabaseExecutionStatement()
315 | {
316 | Script = statementBuilder.ToString(),
317 | ScriptType = scriptType,
318 | MustAffectData = command.Options?.MustAffectData ?? false,
319 | Parameters = parameters,
320 | HasPreScript = false
321 | }
322 | };
323 | }
324 | else
325 | {
326 | var queryStatement = GenerateQueryStatementCore(context, translationResult, QueryableLocation.JoinTarget);
327 | var updateTablePetName = "UTB";
328 | var joinItems = FormatWrapJoinPrimaryKeys(context, command.Queryable, command.GetEntityType(), tablePetName, tablePetName, updateTablePetName);
329 | scriptTemplate = $"{FormatPreScript(context)}UPDATE {tablePetName} SET {string.Join(",", updateSetArray)} FROM {{0}}{TablePetNameKeyword}{tablePetName} INNER JOIN ({queryStatement.Script}){TablePetNameKeyword}{updateTablePetName} ON {string.Join(" AND ", joinItems)};";
330 | var statements = new List(tableNames.Count);
331 | foreach (var tableName in tableNames)
332 | {
333 | statements.Add(new DatabaseExecutionStatement()
334 | {
335 | Script = string.Format(scriptTemplate, WrapKeywordFunc(tableName)),
336 | ScriptType = scriptType,
337 | MustAffectData = command.Options?.MustAffectData ?? false,
338 | Parameters = parameters,
339 | HasPreScript = true
340 | });
341 | }
342 | return statements;
343 | }
344 |
345 |
346 | #endregion
347 | }
348 |
349 | #endregion
350 |
351 | #region Get delete statement
352 |
353 | ///
354 | /// Get delete statement
355 | ///
356 | /// Command resolve context
357 | ///
358 | protected override List GenerateDeleteStatements(DataCommandResolveContext context)
359 | {
360 | var dataCommandExecutionContext = context.DataCommandExecutionContext;
361 | var command = dataCommandExecutionContext.Command;
362 |
363 | #region translate
364 |
365 | var translationResult = Translate(context);
366 | var preScripts = context.GetPreScripts();
367 |
368 | #endregion
369 |
370 | #region script
371 |
372 | var tablePetName = command.Queryable == null ? context.GetNewTablePetName() : context.GetDefaultTablePetName(command.Queryable);
373 | var entityType = dataCommandExecutionContext.Command.GetEntityType();
374 | var tableNames = dataCommandExecutionContext.GetTableNames(command);
375 | ThrowHelper.ThrowInvalidOperationIf(tableNames.IsNullOrEmpty(), $"Get table name failed for {entityType.Name}");
376 |
377 | // parameters
378 | var parameters = ConvertParameter(command.ScriptParameters) ?? new DataCommandParameters();
379 | parameters.Union(context.GetParameters());
380 |
381 | // statement
382 | var scriptType = GetCommandType(command);
383 | string scriptTemplate;
384 | if (preScripts.IsNullOrEmpty())
385 | {
386 | var condition = translationResult?.GetCondition(ConditionStartKeyword);
387 | var join = translationResult?.GetJoin();
388 | scriptTemplate = $"DELETE {tablePetName} FROM {{0}}{TablePetNameKeyword}{tablePetName}{join}{condition};";
389 | var statementBuilder = new StringBuilder();
390 | foreach (var tableName in tableNames)
391 | {
392 | statementBuilder.AppendLine(string.Format(scriptTemplate, WrapKeywordFunc(tableName)));
393 | }
394 | return new List(1)
395 | {
396 | new DatabaseExecutionStatement()
397 | {
398 | Script = statementBuilder.ToString(),
399 | ScriptType = scriptType,
400 | MustAffectData = command.Options?.MustAffectData ?? false,
401 | Parameters = parameters,
402 | HasPreScript = false
403 | }
404 | };
405 | }
406 | else
407 | {
408 | var queryStatement = GenerateQueryStatementCore(context, translationResult, QueryableLocation.JoinTarget);
409 | var updateTablePetName = "UTB";
410 | var joinItems = FormatWrapJoinPrimaryKeys(context, command.Queryable, command.GetEntityType(), tablePetName, tablePetName, updateTablePetName);
411 | scriptTemplate = $"{FormatPreScript(context)}DELETE {tablePetName} FROM {{0}}{TablePetNameKeyword}{tablePetName} INNER JOIN ({queryStatement.Script}){TablePetNameKeyword}{updateTablePetName} ON {string.Join(" AND ", joinItems)};";
412 | var statements = new List(tableNames.Count);
413 | foreach (var tableName in tableNames)
414 | {
415 | statements.Add(new DatabaseExecutionStatement()
416 | {
417 | Script = string.Format(scriptTemplate, WrapKeywordFunc(tableName)),
418 | ScriptType = scriptType,
419 | MustAffectData = command.Options?.MustAffectData ?? false,
420 | Parameters = parameters,
421 | HasPreScript = true
422 | });
423 | }
424 | return statements;
425 | }
426 |
427 | #endregion
428 | }
429 |
430 | #endregion
431 |
432 | #region Get create table statements
433 |
434 | ///
435 | /// Get create table statements
436 | ///
437 | /// Migration command
438 | ///
439 | protected override List GetCreateTableStatements(DatabaseMigrationCommand migrationCommand)
440 | {
441 | var migrationInfo = migrationCommand.MigrationInfo;
442 | if (migrationInfo?.NewTables.IsNullOrEmpty() ?? true)
443 | {
444 | return new List(0);
445 | }
446 | var newTables = migrationInfo.NewTables;
447 | var statements = new List();
448 | var options = migrationCommand.MigrationInfo;
449 | foreach (var newTableInfo in newTables)
450 | {
451 | if (newTableInfo?.EntityType == null || (newTableInfo?.TableNames.IsNullOrEmpty() ?? true))
452 | {
453 | continue;
454 | }
455 | var entityType = newTableInfo.EntityType;
456 | var entityConfig = EntityManager.GetEntityConfiguration(entityType);
457 | ThrowHelper.ThrowFrameworkErrorIf(entityConfig == null, $"Get entity config failed for {entityType.Name}");
458 |
459 | var newFieldScripts = new List();
460 | var primaryKeyNames = new List();
461 | foreach (var field in entityConfig.AllFields)
462 | {
463 | var dataField = DataManager.GetField(SqlServerManager.CurrentDatabaseServerType, entityType, field.Value);
464 | if (dataField is EntityField dataEntityField)
465 | {
466 | var dataFieldName = SqlServerManager.WrapKeyword(dataEntityField.FieldName);
467 | newFieldScripts.Add($"{dataFieldName}{GetSqlDataType(dataEntityField, options)}{GetFieldNullable(dataEntityField, options)}{GetSqlDefaultValue(dataEntityField, options)}");
468 | if (dataEntityField.InRole(FieldRole.PrimaryKey))
469 | {
470 | primaryKeyNames.Add($"{dataFieldName} ASC");
471 | }
472 | }
473 | }
474 | foreach (var tableName in newTableInfo.TableNames)
475 | {
476 | var createTableStatement = new DatabaseExecutionStatement()
477 | {
478 | Script = $"IF NOT EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'{tableName}') AND TYPE IN (N'U')){Environment.NewLine}BEGIN{Environment.NewLine}CREATE TABLE {tableName} ({string.Join(",", newFieldScripts)}{(primaryKeyNames.IsNullOrEmpty() ? "" : $", CONSTRAINT PK_{tableName} PRIMARY KEY CLUSTERED ({string.Join(",", primaryKeyNames)})")}){Environment.NewLine}END;"
479 | };
480 | statements.Add(createTableStatement);
481 |
482 | // Log script
483 | LogExecutionStatement(createTableStatement);
484 | }
485 | }
486 | return statements;
487 | }
488 |
489 | #endregion
490 |
491 | #region Get limit string
492 |
493 | ///
494 | /// Get limit string
495 | ///
496 | /// Offset num
497 | /// Take num
498 | /// Has sort
499 | ///
500 | protected override string GetLimitString(int offsetNum, int takeNum, bool hasSort)
501 | {
502 | if (takeNum < 1)
503 | {
504 | return string.Empty;
505 | }
506 | if (offsetNum < 1 && !hasSort)
507 | {
508 | return $" TOP({takeNum}) ";
509 | }
510 | return $" OFFSET {offsetNum} ROWS FETCH NEXT {takeNum} ROWS ONLY";
511 |
512 | }
513 |
514 | #endregion
515 |
516 | #region Get field sql data type
517 |
518 | ///
519 | /// Get sql data type
520 | ///
521 | /// Field
522 | ///
523 | protected override string GetSqlDataType(EntityField field, MigrationInfo options)
524 | {
525 | ThrowHelper.ThrowArgNullIf(field == null, nameof(field));
526 | var dbTypeName = "";
527 | if (!string.IsNullOrWhiteSpace(field.DbType))
528 | {
529 | dbTypeName = field.DbType;
530 | }
531 | else
532 | {
533 | var dbType = field.DataType.GetDbType();
534 | var length = field.Length;
535 | var precision = field.Precision;
536 | var notFixedLength = options.NotFixedLength || field.HasDbFeature(FieldDbFeature.NotFixedLength);
537 | static int getCharLength(int flength, int defLength) => flength < 1 ? defLength : flength;
538 | switch (dbType)
539 | {
540 | case DbType.AnsiString:
541 | dbTypeName = $"VARCHAR({getCharLength(length, DefaultCharLength)})";
542 | break;
543 | case DbType.AnsiStringFixedLength:
544 | dbTypeName = $"CHAR({getCharLength(length, DefaultCharLength)})";
545 | break;
546 | case DbType.Binary:
547 | dbTypeName = $"VARBINARY({getCharLength(length, DefaultCharLength)})";
548 | break;
549 | case DbType.Boolean:
550 | dbTypeName = "BIT";
551 | break;
552 | case DbType.Byte:
553 | dbTypeName = "TINYINT";
554 | break;
555 | case DbType.Currency:
556 | dbTypeName = "MONEY";
557 | break;
558 | case DbType.Date:
559 | dbTypeName = "DATE";
560 | break;
561 | case DbType.DateTime:
562 | dbTypeName = "DATETIME";
563 | break;
564 | case DbType.DateTime2:
565 | dbTypeName = $"DATETIME2({(length < 1 ? 7 : length)})";
566 | break;
567 | case DbType.DateTimeOffset:
568 | dbTypeName = $"DATETIMEOFFSET({(length < 1 ? 7 : length)})";
569 | break;
570 | case DbType.Decimal:
571 | dbTypeName = $"DECIMAL({(length < 1 ? DefaultDecimalLength : length)}, {(precision < 0 ? DefaultDecimalPrecision : precision)})";
572 | break;
573 | case DbType.Double:
574 | dbTypeName = "FLOAT";
575 | break;
576 | case DbType.Guid:
577 | dbTypeName = "UNIQUEIDENTIFIER";
578 | break;
579 | case DbType.Int16:
580 | case DbType.SByte:
581 | dbTypeName = "SMALLINT";
582 | break;
583 | case DbType.Int32:
584 | case DbType.UInt16:
585 | case DbType.UInt32:
586 | dbTypeName = "INT";
587 | break;
588 | case DbType.Int64:
589 | case DbType.UInt64:
590 | dbTypeName = "BIGINT";
591 | break;
592 | case DbType.Object:
593 | dbTypeName = "SQL_VARIANT";
594 | break;
595 | case DbType.Single:
596 | dbTypeName = "REAL";
597 | break;
598 | case DbType.String:
599 | length = getCharLength(length, DefaultCharLength);
600 | dbTypeName = notFixedLength
601 | ? $"VARCHAR({(length > 8000 ? "MAX" : length.ToString())})"
602 | : $"NVARCHAR ({(length > 4000 ? "MAX" : length.ToString())})";
603 | break;
604 | case DbType.StringFixedLength:
605 | dbTypeName = $"NCHAR({getCharLength(length, DefaultCharLength)})";
606 | break;
607 | case DbType.Time:
608 | dbTypeName = $"TIME({(length < 1 ? 7 : length)})";
609 | break;
610 | case DbType.Xml:
611 | dbTypeName = "XML";
612 | break;
613 | default:
614 | throw new NotSupportedException(dbType.ToString());
615 | }
616 | }
617 | return $" {dbTypeName}";
618 | }
619 |
620 | #endregion
621 | }
622 | }
623 |
--------------------------------------------------------------------------------