├── .editorconfig
├── .gitignore
├── AsyncDataAdapter.Microsoft.Data.SqlClient
├── AsyncDataAdapter.Microsoft.Data.SqlClient.csproj
└── Data
│ ├── BatchingMSqlDataAdapter.cs
│ └── MSSqlAsyncDataAdapter.cs
├── AsyncDataAdapter.System.Data.SqlClient
├── AsyncDataAdapter.System.Data.SqlClient.csproj
└── Data
│ ├── BatchingSqlDataAdapter.cs
│ └── SqlAsyncDataAdapter.cs
├── AsyncDataAdapter.Tests
├── .gitignore
├── AsyncDataAdapter.Tests.csproj
├── FakeDb
│ ├── AsyncMode.cs
│ ├── FakeDbCommand.cs
│ ├── FakeDbCommandBuilder.cs
│ ├── FakeDbConnection.cs
│ ├── FakeDbDataAdapter.cs
│ ├── FakeDbDataReader.cs
│ ├── FakeDbDelays.cs
│ ├── FakeDbParameter.cs
│ ├── FakeDbParameterCollection.cs
│ ├── FakeDbProviderFactory.cs
│ ├── FakeDbTransaction.cs
│ └── ProxiedFakeDb
│ │ └── ProxiedFakeDbDataAdapter.cs
├── Properties
│ └── AssemblyInfo.cs
├── ProxyDataAdapter
│ ├── AsynchronousProxyDataAdapterTests.cs
│ ├── ReentrancyDetectionTests.cs
│ └── SynchronousProxyDataAdapterTests.cs
├── ReflectionTest.cs
├── SingleMethodTests
│ ├── Fill1Test.cs
│ ├── Fill2Test.cs
│ ├── Fill3Test.cs
│ ├── Fill4Test.cs
│ ├── Fill5Test.cs
│ ├── FillSchema1Test.cs
│ ├── FillSchema2Test.cs
│ ├── FillSchema3Test.cs
│ ├── Update1Test.cs
│ ├── Update2Test.cs
│ ├── Update3Test.cs
│ ├── Update4Test.cs
│ └── Utility
│ │ ├── DbDataAdapterMethodOverloads.cs
│ │ └── SingleMethodTest.cs
├── SqlServer
│ ├── MicrosoftDataSqlTests.cs
│ ├── SqlDataAdapterTest.cs
│ └── SystemDataSqlTests.cs
├── TestConfiguration.cs
└── TestUtility
│ ├── DataTableMethods.cs
│ ├── FakeDbCommandBuilderTests.cs
│ ├── FakeDbDataReaderTests.cs
│ ├── RandomDataGenerator.cs
│ ├── RandomDataGeneratorTests.cs
│ └── TestTable.cs
├── AsyncDataAdapter.msbuild
├── AsyncDataAdapter.sln
├── AsyncDataAdapter
├── AsyncDataAdapter.csproj
├── AsyncDataAdapter.snk
└── Data
│ ├── Common
│ ├── AdaDataReaderContainer.cs
│ ├── AdaDbSchemaRow.cs
│ ├── AdaDbSchemaTable.cs
│ ├── AdaSchemaMapping.cs
│ ├── BatchCommandInfo.cs
│ ├── DataTables.cs
│ └── Interfaces
│ │ ├── IAdaSchemaMappingAdapter.cs
│ │ ├── IAsyncDataAdapter.cs
│ │ ├── IBatchingAdapter.cs
│ │ └── IFullDbDataAdapter.cs
│ ├── Core
│ ├── BatchExecute.UpdatedRowStatus.cs
│ ├── BatchExecute.cs
│ ├── BatchingAdapter.cs
│ ├── Connections.cs
│ ├── FillAsync.cs
│ ├── FillLoadDataRowChunk.cs
│ ├── FillMapping.cs
│ ├── FillSchemaAsync.cs
│ ├── ICanUpdateAsync.cs
│ ├── ParameterInputOutput.cs
│ ├── UpdateAsync.cs
│ └── UpdateRowAsync.cs
│ ├── DbCommandBuilder
│ ├── IAsyncDbCommandBuilder.cs
│ └── ProxyDbCommandBuilder.cs
│ ├── Internal
│ ├── Utility.cs
│ └── Validation.cs
│ ├── Reflection
│ ├── DataColumnReflection.cs
│ ├── ReflectedMethods.cs
│ ├── ReflectedMethods.out.cs
│ ├── ReflectedMethods.tt
│ ├── ReflectedMethods.ttold
│ ├── ReflectedProperty.cs
│ ├── Reflection.cs
│ └── RowUpdatedEventArgs.cs
│ └── _DataAdapter
│ ├── AsyncDbDataAdapter.cs
│ ├── ProxyDataAdapter.FillError.cs
│ ├── ProxyDataAdapter.cs
│ ├── ProxyDbDataAdapter.DataAdapter.cs
│ ├── ProxyDbDataAdapter.DbCommandBuilder.cs
│ ├── ProxyDbDataAdapter.DbDataAdapter.cs
│ ├── ProxyDbDataAdapter.FillAsync.cs
│ ├── ProxyDbDataAdapter.FillError.cs
│ ├── ProxyDbDataAdapter.FillSchemaAsync.cs
│ ├── ProxyDbDataAdapter.IAsyncDbDataAdapter.cs
│ ├── ProxyDbDataAdapter.UpdateAsync.cs
│ └── ProxyDbDataAdapter.cs
├── DbSetup.sql
├── LICENSE
├── Properties.xml
├── README.md
├── Tools
└── NuGet.exe
└── appveyor.yml
/.editorconfig:
--------------------------------------------------------------------------------
1 | # To learn more about .editorconfig see https://aka.ms/editorconfigdocs
2 | ###############################
3 | # Core EditorConfig Options #
4 | ###############################
5 | # All files
6 | [*]
7 | indent_style = space
8 | # Code files
9 |
10 | [*.csproj]
11 | indent_size = 2
12 | indent_style = space
13 | insert_final_newline = true
14 | charset = utf-8
15 |
16 | [*.{cs,csx,vb,vbx}]
17 | indent_size = 4
18 | insert_final_newline = true
19 | charset = utf-8
20 | ###############################
21 | # .NET Coding Conventions #
22 | ###############################
23 | [*.{cs,vb}]
24 | # Organize usings
25 | dotnet_sort_system_directives_first = true
26 | # this. preferences
27 | dotnet_style_qualification_for_field = true:suggestion
28 | dotnet_style_qualification_for_property = true:suggestion
29 | dotnet_style_qualification_for_method = true:suggestion
30 | dotnet_style_qualification_for_event = true:suggestion
31 | # Language keywords vs BCL types preferences
32 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent
33 | dotnet_style_predefined_type_for_member_access = true:silent
34 | # Parentheses preferences
35 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
36 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
37 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
38 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
39 | # Modifier preferences
40 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
41 | dotnet_style_readonly_field = true:suggestion
42 | # Expression-level preferences
43 | dotnet_style_object_initializer = true:suggestion
44 | dotnet_style_collection_initializer = true:suggestion
45 | dotnet_style_explicit_tuple_names = true:suggestion
46 | dotnet_style_null_propagation = true:suggestion
47 | dotnet_style_coalesce_expression = true:suggestion
48 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
49 | dotnet_style_prefer_inferred_tuple_names = true:suggestion
50 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
51 | dotnet_style_prefer_auto_properties = true:silent
52 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent
53 | dotnet_style_prefer_conditional_expression_over_return = true:silent
54 | ###############################
55 | # Naming Conventions #
56 | ###############################
57 | # Style Definitions
58 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case
59 | # Use PascalCase for constant fields
60 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
61 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
62 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
63 | dotnet_naming_symbols.constant_fields.applicable_kinds = field
64 | dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
65 | dotnet_naming_symbols.constant_fields.required_modifiers = const
66 | ###############################
67 | # C# Coding Conventions #
68 | ###############################
69 | [*.cs]
70 | # var preferences
71 | csharp_style_var_for_built_in_types = false:suggestion
72 | csharp_style_var_when_type_is_apparent = false:suggestion
73 | csharp_style_var_elsewhere = false:suggestion
74 | # Expression-bodied members
75 | csharp_style_expression_bodied_methods = false:silent
76 | csharp_style_expression_bodied_constructors = false:silent
77 | csharp_style_expression_bodied_operators = false:silent
78 | csharp_style_expression_bodied_properties = true:silent
79 | csharp_style_expression_bodied_indexers = true:silent
80 | csharp_style_expression_bodied_accessors = true:silent
81 | # Pattern matching preferences
82 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
83 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
84 | # Null-checking preferences
85 | csharp_style_throw_expression = true:suggestion
86 | csharp_style_conditional_delegate_call = true:suggestion
87 | # Modifier preferences
88 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
89 | # Expression-level preferences
90 | csharp_prefer_braces = true:silent
91 | csharp_style_deconstructed_variable_declaration = true:suggestion
92 | csharp_prefer_simple_default_expression = true:suggestion
93 | csharp_style_pattern_local_over_anonymous_function = true:suggestion
94 | csharp_style_inlined_variable_declaration = true:suggestion
95 | ###############################
96 | # C# Formatting Rules #
97 | ###############################
98 | # New line preferences
99 | csharp_new_line_before_open_brace = all
100 | csharp_new_line_before_else = true
101 | csharp_new_line_before_catch = true
102 | csharp_new_line_before_finally = true
103 | csharp_new_line_before_members_in_object_initializers = true
104 | csharp_new_line_before_members_in_anonymous_types = true
105 | csharp_new_line_between_query_expression_clauses = true
106 | # Indentation preferences
107 | csharp_indent_case_contents = true
108 | csharp_indent_switch_labels = true
109 | csharp_indent_labels = flush_left
110 | # Space preferences
111 | csharp_space_after_cast = false
112 | csharp_space_after_keywords_in_control_flow_statements = true
113 | csharp_space_between_method_call_parameter_list_parentheses = false
114 | csharp_space_between_method_declaration_parameter_list_parentheses = false
115 | csharp_space_between_parentheses = false
116 | csharp_space_before_colon_in_inheritance_clause = true
117 | csharp_space_after_colon_in_inheritance_clause = true
118 | csharp_space_around_binary_operators = before_and_after
119 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
120 | csharp_space_between_method_call_name_and_opening_parenthesis = false
121 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
122 | # Wrapping preferences
123 | csharp_preserve_single_line_statements = true
124 | csharp_preserve_single_line_blocks = true
125 |
126 |
127 | #####
128 |
129 | dotnet_style_prefer_compound_assignment = false:none
130 | dotnet_style_object_initializer = false:suggestion
131 |
132 | # IDE1006: Naming Styles
133 | dotnet_diagnostic.IDE1006.severity = none
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
254 | TMP/
255 |
256 | ./*.nupkg
257 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Microsoft.Data.SqlClient/AsyncDataAdapter.Microsoft.Data.SqlClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | true
6 | true
7 | StrongName.snk.pfx
8 | true
9 | true
10 | 1591
11 |
12 |
13 | true
14 | snupkg
15 |
16 |
17 | Jehoel.AsyncDataAdapter.Microsoft.Data.SqlClient
18 | https://github.com/Jehoel/AsyncDataAdapter/
19 | MIT
20 | https://github.com/Jehoel/AsyncDataAdapter/
21 | Microsoft Corporation, Vladimir Kloz <vladimir.kloz@gmail.com>; Jeremy Kruer; Dai Rees;
22 | 4.0.0
23 | Vladimir Kloz; Jeremy Kruer; Dai Rees;
24 |
25 | Jehoel.AsyncDataAdapter.Microsoft.Data.SqlClient provides an AsyncDataAdapter for Microsoft.Data.SqlClient
26 | DataAdapter DbDataAdapter SqlDataAdapter AsyncDataAdapter AdaDataAdapter AsyncSqlDataAdapter SqlAsyncDataAdapter FillAsync FillSchemaAsync UpdateAsync
27 | 4.0.0 - Initial release.
28 |
29 |
30 |
31 |
32 |
33 | bin\Release
34 |
35 |
36 |
37 | bin\Debug
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Microsoft.Data.SqlClient/Data/BatchingMSqlDataAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Data.Common;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | using Microsoft.Data.SqlClient;
8 |
9 | namespace AsyncDataAdapter.Internal
10 | {
11 | public class BatchingMSqlDataAdapter : IBatchingAdapter
12 | {
13 | private readonly SqlDataAdapter adapter;
14 |
15 | public BatchingMSqlDataAdapter( SqlDataAdapter adapter )
16 | {
17 | this.adapter = adapter ?? throw new ArgumentNullException(nameof(adapter));
18 | }
19 |
20 | private struct _UpdateMappingAction { }
21 | private struct _UpdateSchemaAction { }
22 | private struct _UpdateBatchSize { }
23 |
24 | public MissingMappingAction UpdateMappingAction => ReflectedProperty.GetValue( this.adapter );
25 | public MissingSchemaAction UpdateSchemaAction => ReflectedProperty.GetValue( this.adapter );
26 | public Int32 UpdateBatchSize => ReflectedProperty.GetValue( this.adapter );
27 |
28 | private struct _AddToBatch { }
29 |
30 | public int AddToBatch(DbCommand command)
31 | {
32 | return ReflectedFunc.Invoke( this.adapter, command );
33 | }
34 |
35 | private struct _ClearBatch { }
36 |
37 | public void ClearBatch()
38 | {
39 | ReflectedAction.Invoke( this.adapter );
40 | }
41 |
42 | private struct _ExecuteBatchAsync { }
43 |
44 | public Task ExecuteBatchAsync(CancellationToken cancellationToken)
45 | {
46 | return ReflectedFunc>.Invoke( this.adapter, cancellationToken );
47 | }
48 |
49 | private struct _TerminateBatching { }
50 |
51 | public void TerminateBatching()
52 | {
53 | ReflectedAction.Invoke( this.adapter );
54 | }
55 |
56 | private struct _GetBatchedParameter { }
57 |
58 | public IDataParameter GetBatchedParameter(int commandIdentifier, int parameterIndex)
59 | {
60 | return ReflectedFunc.Invoke( this.adapter, commandIdentifier, parameterIndex );
61 | }
62 |
63 | private struct _GetBatchedRecordsAffected { }
64 |
65 | public bool GetBatchedRecordsAffected(int commandIdentifier, out int recordsAffected, out Exception error)
66 | {
67 | return ReflectedFuncO2O3.Invoke( this.adapter, commandIdentifier, out recordsAffected, out error );
68 | }
69 |
70 | private struct _InitializeBatching { }
71 |
72 | public void InitializeBatching()
73 | {
74 | ReflectedAction.Invoke( this.adapter );
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Microsoft.Data.SqlClient/Data/MSSqlAsyncDataAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data.Common;
3 |
4 | using Microsoft.Data.SqlClient;
5 |
6 | using AsyncDataAdapter.Internal;
7 |
8 | namespace AsyncDataAdapter
9 | {
10 | using ProxyDbDataAdapterForSqlClient = ProxyDbDataAdapter<
11 | SqlDataAdapter,
12 | SqlConnection,
13 | SqlCommand,
14 | SqlDataReader
15 | >;
16 |
17 | /// For use with (Microsoft.Data.SqlClient, not System.Data.SqlClient).
18 | public sealed class MSSqlAsyncDbDataAdapter : ProxyDbDataAdapterForSqlClient
19 | {
20 | public MSSqlAsyncDbDataAdapter()
21 | : this( original: new SqlDataAdapter() )
22 | {
23 | }
24 |
25 | public MSSqlAsyncDbDataAdapter( SqlCommand selectCommand )
26 | : this( original: new SqlDataAdapter( selectCommand ) )
27 | {
28 | }
29 |
30 | public MSSqlAsyncDbDataAdapter( String selectCommandText, SqlConnection connection )
31 | : this( original: new SqlDataAdapter( selectCommandText, connection ) )
32 | {
33 | }
34 |
35 | public MSSqlAsyncDbDataAdapter( String selectCommandText, String connectionString )
36 | : this( original: new SqlDataAdapter( selectCommandText, connectionString ) )
37 | {
38 | }
39 |
40 | //
41 |
42 | private MSSqlAsyncDbDataAdapter( SqlDataAdapter original )
43 | : this( original: original, batching: new BatchingMSqlDataAdapter( original ) )
44 | {
45 |
46 | }
47 |
48 | private MSSqlAsyncDbDataAdapter( SqlDataAdapter original, BatchingMSqlDataAdapter batching )
49 | : base( batchingAdapter: batching, subject: original )
50 | {
51 | }
52 |
53 | protected override DbCommandBuilder CreateCommandBuilder()
54 | {
55 | return new SqlCommandBuilder( this.Subject );
56 | }
57 | }
58 |
59 | public static class MSSqlClientExtensions
60 | {
61 | /// Creates a new using (the extension method subject) as the . Note that the 's property MUST be non-null. The connection does not need to be in an Open state yet, however.
62 | /// Required. Cannot be null. Must have a valid non-null set.
63 | public static MSSqlAsyncDbDataAdapter CreateAsyncAdapter( this SqlCommand selectCommand )
64 | {
65 | if (selectCommand is null) throw new ArgumentNullException(nameof(selectCommand));
66 |
67 | if( selectCommand.Connection is null ) throw new ArgumentException( message: "The Connection property must be set.", paramName: nameof(selectCommand) );
68 |
69 | return new MSSqlAsyncDbDataAdapter( selectCommand );
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.System.Data.SqlClient/AsyncDataAdapter.System.Data.SqlClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | true
6 | true
7 | StrongName.snk.pfx
8 | true
9 | true
10 | 1591
11 |
12 |
13 | true
14 | snupkg
15 |
16 |
17 | Jehoel.AsyncDataAdapter.System.Data.SqlClient
18 | https://github.com/Jehoel/AsyncDataAdapter/
19 | MIT
20 | https://github.com/Jehoel/AsyncDataAdapter/
21 | Microsoft Corporation, Vladimir Kloz <vladimir.kloz@gmail.com>; Jeremy Kruer; Dai Rees;
22 | 4.0.0
23 | Vladimir Kloz; Jeremy Kruer; Dai Rees;
24 |
25 | Jehoel.AsyncDataAdapter builds on Vladimir Kloz' original AsyncDataAdapter package, with support for .NET Standard 2.0, and numerous other improvements. The original implementation is based on Microsoft's MIT-licensed implementation of DataReader, DbDataReader, and SqlDataReader.
26 | DataAdapter DbDataAdapter SqlDataAdapter AsyncDataAdapter AdaDataAdapter AsyncSqlDataAdapter SqlAsyncDataAdapter FillAsync FillSchemaAsync UpdateAsync
27 | 4.0.0 - Initial release.
28 |
29 |
30 |
31 |
32 |
33 | bin\Release
34 |
35 |
36 |
37 | bin\Debug
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.System.Data.SqlClient/Data/BatchingSqlDataAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Data.Common;
4 | using System.Data.SqlClient;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace AsyncDataAdapter.Internal
9 | {
10 | public class BatchingSqlDataAdapter : IBatchingAdapter
11 | {
12 | private readonly SqlDataAdapter adapter;
13 |
14 | public BatchingSqlDataAdapter( SqlDataAdapter adapter )
15 | {
16 | this.adapter = adapter ?? throw new ArgumentNullException(nameof(adapter));
17 | }
18 |
19 | private struct _UpdateMappingAction { }
20 | private struct _UpdateSchemaAction { }
21 | private struct _UpdateBatchSize { }
22 |
23 | public MissingMappingAction UpdateMappingAction => ReflectedProperty.GetValue( this.adapter );
24 | public MissingSchemaAction UpdateSchemaAction => ReflectedProperty.GetValue( this.adapter );
25 | public Int32 UpdateBatchSize => ReflectedProperty.GetValue( this.adapter );
26 |
27 | private struct _AddToBatch { }
28 |
29 | public int AddToBatch(DbCommand command)
30 | {
31 | return ReflectedFunc.Invoke( this.adapter, command );
32 | }
33 |
34 | private struct _ClearBatch { }
35 |
36 | public void ClearBatch()
37 | {
38 | ReflectedAction.Invoke( this.adapter );
39 | }
40 |
41 | private struct _ExecuteBatchAsync { }
42 |
43 | public Task ExecuteBatchAsync(CancellationToken cancellationToken)
44 | {
45 | return ReflectedFunc>.Invoke( this.adapter, cancellationToken );
46 | }
47 |
48 | private struct _TerminateBatching { }
49 |
50 | public void TerminateBatching()
51 | {
52 | ReflectedAction.Invoke( this.adapter );
53 | }
54 |
55 | private struct _GetBatchedParameter { }
56 |
57 | public IDataParameter GetBatchedParameter(int commandIdentifier, int parameterIndex)
58 | {
59 | return ReflectedFunc.Invoke( this.adapter, commandIdentifier, parameterIndex );
60 | }
61 |
62 | private struct _GetBatchedRecordsAffected { }
63 |
64 | public bool GetBatchedRecordsAffected(int commandIdentifier, out int recordsAffected, out Exception error)
65 | {
66 | return ReflectedFuncO2O3.Invoke( this.adapter, commandIdentifier, out recordsAffected, out error );
67 | }
68 |
69 | private struct _InitializeBatching { }
70 |
71 | public void InitializeBatching()
72 | {
73 | ReflectedAction.Invoke( this.adapter );
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.System.Data.SqlClient/Data/SqlAsyncDataAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data.Common;
3 | using System.Data.SqlClient;
4 |
5 | using AsyncDataAdapter.Internal;
6 |
7 | namespace AsyncDataAdapter
8 | {
9 | using ProxyDbDataAdapterForSqlClient = ProxyDbDataAdapter<
10 | SqlDataAdapter,
11 | SqlConnection,
12 | SqlCommand,
13 | SqlDataReader
14 | >;
15 |
16 | /// For use with (System.Data.SqlClient, not Microsoft.Data.SqlClient).
17 | public sealed class SqlAsyncDbDataAdapter : ProxyDbDataAdapterForSqlClient
18 | {
19 | public SqlAsyncDbDataAdapter()
20 | : this( original: new SqlDataAdapter() )
21 | {
22 | }
23 |
24 | public SqlAsyncDbDataAdapter( SqlCommand selectCommand )
25 | : this( original: new SqlDataAdapter( selectCommand ) )
26 | {
27 | }
28 |
29 | public SqlAsyncDbDataAdapter( String selectCommandText, SqlConnection connection )
30 | : this( original: new SqlDataAdapter( selectCommandText, connection ) )
31 | {
32 | }
33 |
34 | public SqlAsyncDbDataAdapter( String selectCommandText, String connectionString )
35 | : this( original: new SqlDataAdapter( selectCommandText, connectionString ) )
36 | {
37 | }
38 |
39 | //
40 |
41 | private SqlAsyncDbDataAdapter( SqlDataAdapter original )
42 | : this( original: original, batching: new BatchingSqlDataAdapter( original ) )
43 | {
44 |
45 | }
46 |
47 | private SqlAsyncDbDataAdapter( SqlDataAdapter original, BatchingSqlDataAdapter batching )
48 | : base( batchingAdapter: batching, subject: original )
49 | {
50 | }
51 |
52 | protected override DbCommandBuilder CreateCommandBuilder()
53 | {
54 | return new SqlCommandBuilder( this.Subject );
55 | }
56 | }
57 |
58 | public static class SqlClientExtensions
59 | {
60 | /// Creates a new using (the extension method subject) as the . Note that the 's property MUST be non-null. The connection does not need to be in an Open state yet, however.
61 | /// Required. Cannot be null. Must have a valid non-null set.
62 | public static SqlAsyncDbDataAdapter CreateAsyncAdapter( this SqlCommand selectCommand )
63 | {
64 | if (selectCommand is null) throw new ArgumentNullException(nameof(selectCommand));
65 |
66 | if( selectCommand.Connection is null ) throw new ArgumentException( message: "The Connection property must be set.", paramName: nameof(selectCommand) );
67 |
68 | return new SqlAsyncDbDataAdapter( selectCommand );
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/.gitignore:
--------------------------------------------------------------------------------
1 | test-config.json
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/AsyncDataAdapter.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | PreserveNewest
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/FakeDb/AsyncMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace AsyncDataAdapter.Tests
6 | {
7 | [Flags]
8 | public enum AsyncMode
9 | {
10 | None = 0,
11 |
12 | AllowSync = 1,
13 |
14 | /// Do real async work, or if that's not possible then emulate it by awaiting and then calling the synchronous implementation, for example.
15 | AwaitAsync = 2 | 4,
16 |
17 | /// Block the thread using and then directly call the synchronous version. This is meant to simulate crappy fake-async implementations.
18 | BlockAsync = 2 | 8,
19 |
20 | /// If the async method is virtual and already implemented by the framework superclass (e.g. ) then call that method.
21 | BaseAsync = 2 | 16,
22 |
23 | /// Run the logic (sync or async) inside a job.
24 | RunAsync = 2 | 32,
25 |
26 | // This enum design is probably wrong - the 4/8/16 options are meant to be mutually-exclusive, ugh.
27 | }
28 |
29 | public static class Extensions
30 | {
31 | /// Not named AllowSync because it's too similar to .
32 | public static Boolean AllowOld( this AsyncMode value ) => ( (Int32)value & 1 ) == 1;
33 |
34 | public static Boolean AllowAsync( this AsyncMode value ) => ( (Int32)value & 2 ) == 2;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/FakeDb/FakeDbCommandBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Data.Common;
4 | using System.Globalization;
5 |
6 | namespace AsyncDataAdapter.Tests.FakeDb
7 | {
8 | public class FakeDbCommandBuilder : DbCommandBuilder
9 | {
10 | /// This ctor is only used by and should not be called by anyone, ever, really.
11 | internal FakeDbCommandBuilder()
12 | {
13 | base.QuotePrefix = "[";
14 | base.QuoteSuffix = "]";
15 | }
16 |
17 | public FakeDbCommandBuilder( FakeDbDataAdapter adapter )
18 | : base()
19 | {
20 | base.QuotePrefix = "[";
21 | base.QuoteSuffix = "]";
22 | this.DataAdapter = adapter;
23 | }
24 |
25 | protected override void ApplyParameterInfo( DbParameter parameter, DataRow row, StatementType statementType, bool whereClause )
26 | {
27 | // NOOP.
28 | }
29 |
30 | protected override string GetParameterName(int parameterOrdinal)
31 | {
32 | return "@p" + parameterOrdinal.ToString( CultureInfo.InvariantCulture );
33 | }
34 |
35 | protected override string GetParameterName(string parameterName)
36 | {
37 | return "@" + parameterName;
38 | }
39 |
40 | protected override string GetParameterPlaceholder(int parameterOrdinal)
41 | {
42 | return "@p" + parameterOrdinal.ToString(CultureInfo.InvariantCulture);
43 | }
44 |
45 | protected override void SetRowUpdatingHandler(DbDataAdapter adapter)
46 | {
47 | FakeDbDataAdapter fda = (FakeDbDataAdapter)adapter;
48 |
49 | if (fda == base.DataAdapter)
50 | {
51 | // fda.RowUpdating -= this.RowUpdatingHandler;
52 | }
53 | else
54 | {
55 | // fda.RowUpdating += this.RowUpdatingHandler;
56 | }
57 | }
58 |
59 | // Why aren't these methods abstract? The default impl always throws.
60 | public override string QuoteIdentifier(string unquotedIdentifier)
61 | {
62 | if( String.IsNullOrWhiteSpace( unquotedIdentifier ) ) return unquotedIdentifier;
63 |
64 | return '[' + unquotedIdentifier.Trim( '[', ']' ) + ']';
65 | }
66 |
67 | public override string UnquoteIdentifier(string quotedIdentifier)
68 | {
69 | if( String.IsNullOrWhiteSpace( quotedIdentifier ) ) return quotedIdentifier;
70 |
71 | return quotedIdentifier.Trim( '[', ']' );
72 | }
73 |
74 | //
75 |
76 | public new FakeDbCommand GetUpdateCommand() => (FakeDbCommand)base.GetUpdateCommand();
77 |
78 | public new FakeDbCommand GetUpdateCommand( Boolean useColumnsForParameterNames ) => (FakeDbCommand)base.GetUpdateCommand( useColumnsForParameterNames );
79 |
80 | //
81 |
82 | public new FakeDbCommand GetDeleteCommand() => (FakeDbCommand)base.GetDeleteCommand();
83 |
84 | public new FakeDbCommand GetDeleteCommand( Boolean useColumnsForParameterNames ) => (FakeDbCommand)base.GetDeleteCommand( useColumnsForParameterNames );
85 |
86 | //
87 |
88 | public new FakeDbCommand GetInsertCommand() => (FakeDbCommand)base.GetInsertCommand();
89 |
90 | public new FakeDbCommand GetInsertCommand( Boolean useColumnsForParameterNames ) => (FakeDbCommand)base.GetInsertCommand( useColumnsForParameterNames );
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/FakeDb/FakeDbDataAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data;
4 | using System.Data.Common;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | using AsyncDataAdapter.Internal;
9 |
10 | namespace AsyncDataAdapter.Tests.FakeDb
11 | {
12 | /// NOTE: This does not implement . For that, see .
13 | public class FakeDbDataAdapter : DbDataAdapter, IFullDbDataAdapter
14 | {
15 | // TODO: Override every, single, method - and add call-counts.
16 |
17 | /// This ctor is only used by and should not be called by anyone, ever, really.
18 | internal FakeDbDataAdapter()
19 | {
20 | }
21 |
22 | /// The is required before can be used.
23 | public FakeDbDataAdapter( FakeDbCommand select )
24 | : base()
25 | {
26 | this.SelectCommand = select ?? throw new ArgumentNullException(nameof(select));
27 | }
28 |
29 | /// The is required before can be used.
30 | public FakeDbDataAdapter( FakeDbCommand select, FakeDbCommand update, FakeDbCommand insert, FakeDbCommand delete )
31 | : this( select )
32 | {
33 | this.UpdateCommand = update ?? throw new ArgumentNullException(nameof(update));
34 | this.InsertCommand = insert ?? throw new ArgumentNullException(nameof(insert));
35 | this.DeleteCommand = delete ?? throw new ArgumentNullException(nameof(delete));
36 | }
37 |
38 | public new FakeDbCommand UpdateCommand
39 | {
40 | get => (FakeDbCommand)base.UpdateCommand;
41 | set => base.UpdateCommand = value;
42 | }
43 |
44 | public FakeDbCommandBuilder CreateCommandBuilder()
45 | {
46 | return new FakeDbCommandBuilder( this );
47 | }
48 | }
49 |
50 | public class BatchingFakeDbDataAdapter : FakeDbDataAdapter /*DbDataAdapter*/, IBatchingAdapter
51 | {
52 | // TODO: Override every, single, method - and add call-counts.
53 |
54 | /// The is required before can be used.
55 | public BatchingFakeDbDataAdapter( FakeDbCommand select )
56 | : base( select )
57 | {
58 | }
59 |
60 | /// The is required before can be used.
61 | public BatchingFakeDbDataAdapter( FakeDbCommand select, FakeDbCommand update, FakeDbCommand insert, FakeDbCommand delete )
62 | : base( select, update, insert, delete )
63 | {
64 | }
65 |
66 | #region IBatchingAdapter
67 | // Btw, don't confuse *Update*FooAction with *Missing*FooAction.
68 |
69 | public MissingMappingAction UpdateMappingAction => BatchingAdapterMethods.UpdateMappingAction( base.MissingMappingAction );
70 | public MissingSchemaAction UpdateSchemaAction => BatchingAdapterMethods.UpdateSchemaAction ( base.MissingSchemaAction );
71 |
72 | public List BatchList { get; set; } = new List();
73 |
74 | public int AddToBatch(DbCommand command)
75 | {
76 | this.BatchList.Add( command );
77 | return this.BatchList.Count;
78 | }
79 |
80 | void IBatchingAdapter.ClearBatch()
81 | {
82 | this.BatchList.Clear();
83 | }
84 |
85 | public Task ExecuteBatchAsync(CancellationToken cancellationToken)
86 | {
87 | throw new NotImplementedException();
88 | }
89 |
90 | void IBatchingAdapter.TerminateBatching()
91 | {
92 | throw new NotImplementedException();
93 | }
94 |
95 | IDataParameter IBatchingAdapter.GetBatchedParameter(int commandIdentifier, int parameterIndex)
96 | {
97 | return this.BatchList[commandIdentifier].Parameters[parameterIndex];
98 | }
99 |
100 | bool IBatchingAdapter.GetBatchedRecordsAffected(int commandIdentifier, out int recordsAffected, out Exception error)
101 | {
102 | throw new NotImplementedException();
103 | }
104 |
105 | void IBatchingAdapter.InitializeBatching()
106 | {
107 | throw new NotImplementedException();
108 | }
109 |
110 | #endregion
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/FakeDb/FakeDbDelays.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace AsyncDataAdapter.Tests.FakeDb
6 | {
7 | public class FakeDbDelays
8 | {
9 | public static FakeDbDelays DefaultDelaysNone { get; } = new FakeDbDelays(
10 | connect : null,
11 | execute : null,
12 | transact: null,
13 | result : null,
14 | row : null
15 | );
16 |
17 | public static FakeDbDelays DefaultDelays1MS { get; } = new FakeDbDelays(
18 | connect : TimeSpan.FromMilliseconds(1),
19 | execute : TimeSpan.FromMilliseconds(1),
20 | transact: TimeSpan.FromMilliseconds(1),
21 | result : TimeSpan.FromMilliseconds(1),
22 | row : TimeSpan.FromMilliseconds(1)
23 | );
24 |
25 | public FakeDbDelays(TimeSpan? connect, TimeSpan? execute, TimeSpan? transact, TimeSpan? result, TimeSpan? row)
26 | {
27 | this.Connect = connect;
28 | this.Execute = execute;
29 | this.Transact = transact;
30 | this.Result = result;
31 | this.Row = row;
32 | }
33 |
34 | public TimeSpan? Connect { get; }
35 | public TimeSpan? Execute { get; }
36 | public TimeSpan? Transact { get; }
37 | public TimeSpan? Result { get; }
38 | public TimeSpan? Row { get; }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/FakeDb/FakeDbParameter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Data.Common;
4 |
5 | namespace AsyncDataAdapter.Tests.FakeDb
6 | {
7 | public class FakeDbParameter : DbParameter
8 | {
9 | public FakeDbParameter()
10 | {
11 | }
12 |
13 | public FakeDbParameter( String name, DbType dbType )
14 | {
15 | this.ParameterName = name;
16 | this.DbType = dbType;
17 | }
18 |
19 | public override void ResetDbType()
20 | {
21 | this.DbType = DbType.String;
22 | }
23 |
24 | public override DbType DbType { get; set; } = DbType.String;
25 | public override ParameterDirection Direction { get; set; } = ParameterDirection.Input;
26 | public override Boolean IsNullable { get; set; } = true;
27 | public override String ParameterName { get; set; } = "?";
28 | public override Int32 Size { get; set; }
29 | public override String SourceColumn { get; set; }
30 | public override Boolean SourceColumnNullMapping { get; set; }
31 | public override Object Value { get; set; }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/FakeDb/FakeDbParameterCollection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Data.Common;
6 |
7 | namespace AsyncDataAdapter.Tests.FakeDb
8 | {
9 | public class FakeDbParameterCollection : DbParameterCollection
10 | {
11 | private readonly Object listLock = new Object();
12 | private readonly List list = new List();
13 |
14 | public override int Add(object value)
15 | {
16 | if( value is FakeDbParameter p )
17 | {
18 | this.list.Add( p );
19 | return this.list.Count;
20 | }
21 | else
22 | {
23 | throw new ArgumentException( "Argument is null or is the wrong type." );
24 | }
25 | }
26 |
27 | public override void AddRange(Array values)
28 | {
29 | foreach( Object obj in values )
30 | {
31 | _ = this.Add( obj );
32 | }
33 | }
34 |
35 | public override void Clear()
36 | {
37 | this.list.Clear();
38 | }
39 |
40 | public override bool Contains(object value)
41 | {
42 | if( value is FakeDbParameter p )
43 | {
44 | return this.list.Contains( p );
45 | }
46 | else
47 | {
48 | return false;
49 | }
50 | }
51 |
52 | public override bool Contains(string value)
53 | {
54 | return this.list.Any( p => p.ParameterName == value );
55 | }
56 |
57 | public override void CopyTo(Array array, int index)
58 | {
59 | FakeDbParameter[] a2 = (FakeDbParameter[])array;
60 |
61 | this.list.CopyTo( a2, index );
62 | }
63 |
64 | public override IEnumerator GetEnumerator()
65 | {
66 | return this.list.GetEnumerator();
67 | }
68 |
69 | protected override DbParameter GetParameter(int index)
70 | {
71 | return this.list[index];
72 | }
73 |
74 | protected override DbParameter GetParameter(string parameterName)
75 | {
76 | return this.list.SingleOrDefault( p => p.ParameterName == parameterName );
77 | }
78 |
79 | public override int IndexOf(object value)
80 | {
81 | if( value is FakeDbParameter p )
82 | {
83 | return this.list.IndexOf( p );
84 | }
85 |
86 | return -1;
87 | }
88 |
89 | public override int IndexOf(string parameterName)
90 | {
91 | var match = this.list
92 | .Select( ( p, idx ) => ( p, idx ) )
93 | .SingleOrDefault( t => t.p.ParameterName == parameterName );
94 |
95 | if( match != default )
96 | {
97 | return match.idx;
98 | }
99 |
100 | return -1;
101 | }
102 |
103 | public override void Insert(int index, object value)
104 | {
105 | if( value is FakeDbParameter p )
106 | {
107 | this.list.Insert( index, p );
108 | }
109 | else
110 | {
111 | throw new ArgumentException( "Null or incorrect parameter type." );
112 | }
113 | }
114 |
115 | public override void Remove(object value)
116 | {
117 | if( value is FakeDbParameter p )
118 | {
119 | _ = this.list.Remove( p );
120 | }
121 | else
122 | {
123 | throw new ArgumentException( "Null or incorrect parameter type." );
124 | }
125 | }
126 |
127 | public override void RemoveAt(int index)
128 | {
129 | this.list.RemoveAt( index );
130 | }
131 |
132 | public override void RemoveAt(string parameterName)
133 | {
134 | var match = this.list
135 | .Select( ( p, idx ) => ( p, idx ) )
136 | .SingleOrDefault( t => t.p.ParameterName == parameterName );
137 |
138 | if( match != default )
139 | {
140 | this.list.RemoveAt( match.idx );
141 | }
142 | }
143 |
144 | protected override void SetParameter(int index, DbParameter value)
145 | {
146 | if( value is FakeDbParameter p )
147 | {
148 | this.list[ index ] = p;
149 | }
150 | else
151 | {
152 | throw new ArgumentException( "Null or incorrect parameter type." );
153 | }
154 | }
155 |
156 | protected override void SetParameter(string parameterName, DbParameter value)
157 | {
158 | if( value is FakeDbParameter p )
159 | {
160 | var match = this.list
161 | .Select( ( p, idx ) => ( p, idx ) )
162 | .SingleOrDefault( t => t.p.ParameterName == parameterName );
163 |
164 | if( match != default )
165 | {
166 | this.list[ match.idx ] = p;
167 | }
168 | }
169 | else
170 | {
171 | throw new ArgumentException( "Null or incorrect parameter type." );
172 | }
173 | }
174 |
175 | public override int Count => this.list.Count;
176 |
177 | public override object SyncRoot => this.listLock;
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/FakeDb/FakeDbProviderFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Common;
4 |
5 | namespace AsyncDataAdapter.Tests.FakeDb
6 | {
7 | public class FakeDbProviderFactory : DbProviderFactory
8 | {
9 | public static FakeDbProviderFactory Instance { get; } = new FakeDbProviderFactory();
10 |
11 | private FakeDbProviderFactory()
12 | {
13 | }
14 |
15 | public override bool CanCreateDataSourceEnumerator => false;
16 |
17 | public override bool CanCreateCommandBuilder => true;
18 |
19 | public override bool CanCreateDataAdapter => true;
20 |
21 | public override DbCommand CreateCommand()
22 | {
23 | return new FakeDbCommand();
24 | }
25 |
26 | public FakeDbCommand CreateCommand( FakeDbConnection connection, List testTables, FakeDbDelays delays )
27 | {
28 | return new FakeDbCommand( connection: connection, testTables: testTables, delays )
29 | {
30 | AsyncMode = connection.AsyncMode
31 | };
32 | }
33 |
34 | public override DbCommandBuilder CreateCommandBuilder()
35 | {
36 | return new FakeDbCommandBuilder();
37 | }
38 |
39 | public override DbConnection CreateConnection()
40 | {
41 | // Make this one fail every time, so we can be sure `CreateConnection` is never used without us knowing!
42 | // ...or just fail?
43 | throw new NotSupportedException();
44 |
45 | //return new FakeDbConnection( asyncMode: AsyncMode.None, openDelayMS: -1, executeDelayMS: -1, readDelayMS: -1 );
46 | }
47 |
48 | public override DbConnectionStringBuilder CreateConnectionStringBuilder()
49 | {
50 | // return new FakeDbConnectionStringBuilder();
51 | return base.CreateConnectionStringBuilder();
52 | }
53 |
54 | public override DbDataAdapter CreateDataAdapter()
55 | {
56 | return new FakeDbDataAdapter();
57 | }
58 |
59 | public override DbDataSourceEnumerator CreateDataSourceEnumerator()
60 | {
61 | // return new FakeDbDataSourceEnumerator();
62 | return base.CreateDataSourceEnumerator();
63 | }
64 |
65 | public override DbParameter CreateParameter()
66 | {
67 | return new FakeDbParameter();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/FakeDb/FakeDbTransaction.cs:
--------------------------------------------------------------------------------
1 | using System.Data;
2 | using System.Data.Common;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace AsyncDataAdapter.Tests.FakeDb
7 | {
8 | public class FakeDbTransaction : DbTransaction
9 | {
10 | public FakeDbTransaction( FakeDbConnection c, IsolationLevel level )
11 | : base()
12 | {
13 | this.DbConnection = c;
14 | this.IsolationLevel = level;
15 | }
16 |
17 | protected override DbConnection DbConnection { get; }
18 |
19 | public override IsolationLevel IsolationLevel { get; }
20 |
21 | public override void Commit()
22 | {
23 | }
24 |
25 | public override Task CommitAsync(CancellationToken cancellationToken = default)
26 | {
27 | return Task.CompletedTask;
28 | }
29 |
30 | public override void Rollback()
31 | {
32 | }
33 |
34 | public override Task RollbackAsync(CancellationToken cancellationToken = default)
35 | {
36 | return Task.CompletedTask;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/FakeDb/ProxiedFakeDb/ProxiedFakeDbDataAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Data.Common;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | using AsyncDataAdapter.Internal;
8 |
9 | namespace AsyncDataAdapter.Tests.FakeDb
10 | {
11 | public sealed class FakeProxiedDbDataAdapter : ProxyDbDataAdapter, IFullDbDataAdapter, IFullAsyncDbDataAdapter
12 | {
13 | public FakeProxiedDbDataAdapter( FakeDbCommand selectCmd )
14 | : base( subject: new FakeDbDataAdapter( selectCmd ), batchingAdapter: null )
15 | {
16 | }
17 |
18 | protected override DbCommandBuilder CreateCommandBuilder()
19 | {
20 | return new FakeDbCommandBuilder( this.Subject );
21 | }
22 | }
23 |
24 | public sealed class BatchingFakeProxiedDbDataAdapter : ProxyDbDataAdapter, IFullDbDataAdapter, IFullAsyncDbDataAdapter
25 | {
26 | public BatchingFakeProxiedDbDataAdapter( FakeDbCommand selectCmd )
27 | : this( adp: new BatchingFakeDbDataAdapter( selectCmd ) )
28 | {
29 |
30 | }
31 |
32 | private BatchingFakeProxiedDbDataAdapter( BatchingFakeDbDataAdapter adp )
33 | : base( subject: adp, batchingAdapter: adp )
34 | {
35 | }
36 |
37 | protected override DbCommandBuilder CreateCommandBuilder()
38 | {
39 | return new FakeDbCommandBuilder( this.Subject );
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyCopyright("Copyright © Microsoft 2016")]
10 | [assembly: AssemblyTrademark("")]
11 | [assembly: AssemblyCulture("")]
12 |
13 | // Setting ComVisible to false makes the types in this assembly not visible
14 | // to COM components. If you need to access a type in this assembly from
15 | // COM, set the ComVisible attribute to true on that type.
16 | [assembly: ComVisible(false)]
17 |
18 | // The following GUID is for the ID of the typelib if this project is exposed to COM
19 | [assembly: Guid("34b7e6f3-858a-489b-bdd0-45cc6eb62551")]
20 |
21 | // Version information for an assembly consists of the following four values:
22 | //
23 | // Major Version
24 | // Minor Version
25 | // Build Number
26 | // Revision
27 | //
28 | // You can specify all the values or you can default the Build and Revision Numbers
29 | // by using the '*' as shown below:
30 | // [assembly: AssemblyVersion("1.0.*")]
31 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/ProxyDataAdapter/ReentrancyDetectionTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data;
4 | using System.Data.Common;
5 |
6 | using NUnit.Framework;
7 |
8 | using Shouldly;
9 |
10 | using AsyncDataAdapter.Tests.FakeDb;
11 |
12 | namespace AsyncDataAdapter.Tests
13 | {
14 | public class ReentrancyDetectionTests
15 | {
16 | private static void FiddleWithPropertiesAsFakeProxiedDbDataAdapter( FakeProxiedDbDataAdapter adapter )
17 | {
18 | {
19 | FakeDbCommand cmd = adapter.SelectCommand;
20 | adapter.SelectCommand = null;
21 | adapter.SelectCommand = cmd;
22 | }
23 |
24 | {
25 | FakeDbCommand cmd = adapter.InsertCommand;
26 | adapter.InsertCommand = null;
27 | adapter.InsertCommand = cmd;
28 | }
29 |
30 | {
31 | FakeDbCommand cmd = adapter.DeleteCommand;
32 | adapter.DeleteCommand = null;
33 | adapter.DeleteCommand = cmd;
34 | }
35 |
36 | {
37 | FakeDbCommand cmd = adapter.UpdateCommand;
38 | adapter.UpdateCommand = null;
39 | adapter.UpdateCommand = cmd;
40 | }
41 | }
42 |
43 | private static void FiddleWithPropertiesAsFakeDbDataAdapter( FakeDbDataAdapter adapter )
44 | {
45 | {
46 | FakeDbCommand cmd = (FakeDbCommand)adapter.SelectCommand;
47 | adapter.SelectCommand = null;
48 | adapter.SelectCommand = cmd;
49 | }
50 |
51 | {
52 | FakeDbCommand cmd = (FakeDbCommand)adapter.InsertCommand;
53 | adapter.InsertCommand = null;
54 | adapter.InsertCommand = cmd;
55 | }
56 |
57 | {
58 | FakeDbCommand cmd = (FakeDbCommand)adapter.DeleteCommand;
59 | adapter.DeleteCommand = null;
60 | adapter.DeleteCommand = cmd;
61 | }
62 |
63 | {
64 | FakeDbCommand cmd = (FakeDbCommand)adapter.UpdateCommand;
65 | adapter.UpdateCommand = null;
66 | adapter.UpdateCommand = cmd;
67 | }
68 | }
69 |
70 | private static void FiddleWithPropertiesAsDbDataAdapter( DbDataAdapter adapter )
71 | {
72 | {
73 | FakeDbCommand cmd = (FakeDbCommand)adapter.SelectCommand;
74 | adapter.SelectCommand = null;
75 | adapter.SelectCommand = cmd;
76 | }
77 |
78 | {
79 | FakeDbCommand cmd = (FakeDbCommand)adapter.InsertCommand;
80 | adapter.InsertCommand = null;
81 | adapter.InsertCommand = cmd;
82 | }
83 |
84 | {
85 | FakeDbCommand cmd = (FakeDbCommand)adapter.DeleteCommand;
86 | adapter.DeleteCommand = null;
87 | adapter.DeleteCommand = cmd;
88 | }
89 |
90 | {
91 | FakeDbCommand cmd = (FakeDbCommand)adapter.UpdateCommand;
92 | adapter.UpdateCommand = null;
93 | adapter.UpdateCommand = cmd;
94 | }
95 | }
96 |
97 | private static void FiddleWithPropertiesAsIDbDataAdapter( IDbDataAdapter adapter )
98 | {
99 | {
100 | FakeDbCommand cmd = (FakeDbCommand)adapter.SelectCommand;
101 | adapter.SelectCommand = null;
102 | adapter.SelectCommand = cmd;
103 | }
104 |
105 | {
106 | FakeDbCommand cmd = (FakeDbCommand)adapter.InsertCommand;
107 | adapter.InsertCommand = null;
108 | adapter.InsertCommand = cmd;
109 | }
110 |
111 | {
112 | FakeDbCommand cmd = (FakeDbCommand)adapter.DeleteCommand;
113 | adapter.DeleteCommand = null;
114 | adapter.DeleteCommand = cmd;
115 | }
116 |
117 | {
118 | FakeDbCommand cmd = (FakeDbCommand)adapter.UpdateCommand;
119 | adapter.UpdateCommand = null;
120 | adapter.UpdateCommand = cmd;
121 | }
122 | }
123 |
124 | [Test]
125 | public void FakeDbDataAdapter_properties_should_not_have_infinite_loops_and_stack_overflows()
126 | {
127 | List randomDataSource = RandomDataGenerator.CreateRandomTables( seed: 1, tableCount: 2, /*allowZeroRowsInTablesByIdx: */ 1, 3 );
128 |
129 | // Test that .Dispose() works (DbDataAdapter clears mutable properties in its disposal method)
130 | using( FakeDbConnection connection = new FakeDbConnection( asyncMode: AsyncMode.AllowSync ) )
131 | using( FakeDbCommand selectCommand = connection.CreateCommand( testTables: randomDataSource ) )
132 | using( FakeDbDataAdapter adapter = new FakeDbDataAdapter( selectCommand ) )
133 | {
134 | }
135 |
136 | using( FakeDbConnection connection = new FakeDbConnection( asyncMode: AsyncMode.AllowSync ) )
137 | using( FakeDbCommand selectCommand1 = connection.CreateCommand( testTables: randomDataSource ) )
138 | using( FakeDbCommand selectCommand2 = connection.CreateCommand( testTables: randomDataSource ) )
139 | using( FakeDbDataAdapter adapter = new FakeDbDataAdapter( selectCommand1 ) )
140 | {
141 | using( FakeProxiedDbDataAdapter prox = new FakeProxiedDbDataAdapter( selectCommand1 ) )
142 | {
143 | FiddleWithPropertiesAsFakeProxiedDbDataAdapter( prox );
144 |
145 | FiddleWithPropertiesAsFakeDbDataAdapter( prox );
146 |
147 | FiddleWithPropertiesAsDbDataAdapter( prox );
148 |
149 | FiddleWithPropertiesAsIDbDataAdapter( prox );
150 | }
151 |
152 | FiddleWithPropertiesAsFakeDbDataAdapter( adapter );
153 |
154 | FiddleWithPropertiesAsDbDataAdapter( adapter );
155 |
156 | FiddleWithPropertiesAsIDbDataAdapter( adapter );
157 | }
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/ReflectionTest.cs:
--------------------------------------------------------------------------------
1 | using System.Data;
2 | using System.Data.Common;
3 |
4 | using NUnit.Framework;
5 |
6 | using AsyncDataAdapter.Internal;
7 |
8 | namespace AsyncDataAdapter.Tests
9 | {
10 | [TestFixture]
11 | public class ReflectionTest
12 | {
13 | [Test]
14 | public void AdapterInitIntShouldWork()
15 | {
16 | var e = new RowUpdatedEventArgs(null, null, StatementType.Select, null);
17 |
18 | Assert.DoesNotThrow(() => e.AdapterInit_( recordsAffected: 10 ) );
19 | }
20 |
21 | [Test]
22 | public void AdapterInitDataRowArrayShouldWork()
23 | {
24 | var e = new RowUpdatedEventArgs(null, null, StatementType.Select, null);
25 |
26 | Assert.DoesNotThrow(() => e.AdapterInit_( dataRows: new DataRow[0] ) );
27 | }
28 |
29 | [Test]
30 | public void GetRowsShouldWork()
31 | {
32 | var t = new DataTable();
33 |
34 | var dataRow = t.NewRow();
35 |
36 | var e = new RowUpdatedEventArgs(null, null, StatementType.Select, null);
37 | e.AdapterInit_(new []{dataRow});
38 |
39 | var rows = e.GetRows_();
40 |
41 | Assert.AreEqual(1, rows.Length);
42 | Assert.AreEqual(dataRow, rows[0]);
43 | }
44 |
45 | [Test]
46 | public void GetRowsForSingleRowShouldWork()
47 | {
48 | var t = new DataTable();
49 |
50 | var dataRow = t.NewRow();
51 |
52 | var e = new RowUpdatedEventArgs(null, null, StatementType.Select, null);
53 | e.AdapterInit_(new []{dataRow});
54 |
55 | var row = e.GetRow_(0);
56 |
57 | Assert.AreEqual(dataRow, row);
58 | }
59 |
60 | [Test]
61 | public void EnsureAdditionalCapacityShouldWork()
62 | {
63 | var c = new DataTable().Columns;
64 |
65 | Assert.DoesNotThrow(() => c.EnsureAdditionalCapacity_(10));
66 | }
67 |
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/Fill1Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | using Shouldly;
7 |
8 | using AsyncDataAdapter.Tests.FakeDb;
9 | using NUnit.Framework;
10 |
11 | namespace AsyncDataAdapter.Tests.Big3
12 | {
13 | public class Fill1Test : SingleMethodTest
14 | {
15 | protected override DataSet RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
16 | {
17 | DataSet dataSet = new DataSet();
18 |
19 | Int32 rowsInFirstTable = adapter.Fill1( dataSet );
20 | rowsInFirstTable.ShouldBe( 40 );
21 |
22 | return dataSet;
23 | }
24 |
25 | protected override DataSet RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
26 | {
27 | DataSet dataSet = new DataSet();
28 |
29 | Int32 rowsInFirstTable = adapter.Fill1( dataSet );
30 | rowsInFirstTable.ShouldBe( 40 );
31 |
32 | return dataSet;
33 | }
34 |
35 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
36 | {
37 | DataSet dataSet = new DataSet();
38 |
39 | Int32 rowsInFirstTable = await adapter.Fill1Async( dataSet );
40 | rowsInFirstTable.ShouldBe( 40 );
41 |
42 | return dataSet;
43 | }
44 |
45 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
46 | {
47 | DataSet dataSet = new DataSet();
48 |
49 | Int32 rowsInFirstTable = await adapter.Fill1Async( dataSet );
50 | rowsInFirstTable.ShouldBe( 40 );
51 |
52 | return dataSet;
53 | }
54 |
55 | protected override void AssertResult(DataSet dbSynchronous, DataSet dbProxied, DataSet dbProxiedAsync, DataSet dbBatchingProxiedAsync)
56 | {
57 | DataTableMethods.DataSetEquals( dbSynchronous, dbProxied , out String diffs1 ).ShouldBeTrue( customMessage: diffs1 );
58 | DataTableMethods.DataSetEquals( dbSynchronous, dbProxiedAsync , out String diffs2 ).ShouldBeTrue( customMessage: diffs2 );
59 | DataTableMethods.DataSetEquals( dbSynchronous, dbBatchingProxiedAsync, out String diffs3 ).ShouldBeTrue( customMessage: diffs3 );
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/Fill2Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | using Shouldly;
7 |
8 | using AsyncDataAdapter.Tests.FakeDb;
9 |
10 | namespace AsyncDataAdapter.Tests.Big3
11 | {
12 | public class Fill2Test : SingleMethodTest
13 | {
14 | protected override DataSet RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
15 | {
16 | DataSet dataSet = new DataSet();
17 |
18 | Int32 rowsInFirstTable = adapter.Fill2( dataSet, srcTable: "Foobar" );
19 | rowsInFirstTable.ShouldBe( 40 );
20 |
21 | return dataSet;
22 | }
23 |
24 | protected override DataSet RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
25 | {
26 | DataSet dataSet = new DataSet();
27 |
28 | Int32 rowsInFirstTable = adapter.Fill2( dataSet, srcTable: "Foobar" );
29 | rowsInFirstTable.ShouldBe( 40 );
30 |
31 | return dataSet;
32 | }
33 |
34 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
35 | {
36 | DataSet dataSet = new DataSet();
37 |
38 | Int32 rowsInFirstTable = await adapter.Fill2Async( dataSet, srcTable: "Foobar" );
39 | rowsInFirstTable.ShouldBe( 40 );
40 |
41 | return dataSet;
42 | }
43 |
44 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
45 | {
46 | DataSet dataSet = new DataSet();
47 |
48 | Int32 rowsInFirstTable = await adapter.Fill2Async( dataSet, srcTable: "Foobar" );
49 | rowsInFirstTable.ShouldBe( 40 );
50 |
51 | return dataSet;
52 | }
53 |
54 | protected override void AssertResult(DataSet dbSynchronous, DataSet dbProxied, DataSet dbProxiedAsync, DataSet dbBatchingProxiedAsync)
55 | {
56 | DataTableMethods.DataSetEquals( dbSynchronous, dbProxied , out String diffs1 ).ShouldBeTrue( customMessage: diffs1 );
57 | DataTableMethods.DataSetEquals( dbSynchronous, dbProxiedAsync , out String diffs2 ).ShouldBeTrue( customMessage: diffs2 );
58 | DataTableMethods.DataSetEquals( dbSynchronous, dbBatchingProxiedAsync, out String diffs3 ).ShouldBeTrue( customMessage: diffs3 );
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/Fill3Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | using Shouldly;
7 |
8 | using AsyncDataAdapter.Tests.FakeDb;
9 |
10 | namespace AsyncDataAdapter.Tests.Big3
11 | {
12 | public class Fill3Test : SingleMethodTest
13 | {
14 | protected override DataSet RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
15 | {
16 | DataSet dataSet = new DataSet();
17 |
18 | Int32 rowsInFirstTable = adapter.Fill3( dataSet, startRecord: 5, maxRecords: 10, srcTable: "Barqux" );
19 | rowsInFirstTable.ShouldBe( 10 );
20 |
21 | return dataSet;
22 | }
23 |
24 | protected override DataSet RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
25 | {
26 | DataSet dataSet = new DataSet();
27 |
28 | Int32 rowsInFirstTable = adapter.Fill3( dataSet, startRecord: 5, maxRecords: 10, srcTable: "Barqux" );
29 | rowsInFirstTable.ShouldBe( 10 );
30 |
31 | return dataSet;
32 | }
33 |
34 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
35 | {
36 | DataSet dataSet = new DataSet();
37 |
38 | Int32 rowsInFirstTable = await adapter.Fill3Async( dataSet, startRecord: 5, maxRecords: 10, srcTable: "Barqux" );
39 | rowsInFirstTable.ShouldBe( 10 );
40 |
41 | return dataSet;
42 | }
43 |
44 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
45 | {
46 | DataSet dataSet = new DataSet();
47 |
48 | Int32 rowsInFirstTable = await adapter.Fill3Async( dataSet, startRecord: 5, maxRecords: 10, srcTable: "Barqux" );
49 | rowsInFirstTable.ShouldBe( 10 );
50 |
51 | return dataSet;
52 | }
53 |
54 | protected override void AssertResult(DataSet dbSynchronous, DataSet dbProxied, DataSet dbProxiedAsync, DataSet dbBatchingProxiedAsync)
55 | {
56 | DataTableMethods.DataSetEquals( dbSynchronous, dbProxied , out String diffs1 ).ShouldBeTrue( customMessage: diffs1 );
57 | DataTableMethods.DataSetEquals( dbSynchronous, dbProxiedAsync , out String diffs2 ).ShouldBeTrue( customMessage: diffs2 );
58 | DataTableMethods.DataSetEquals( dbSynchronous, dbBatchingProxiedAsync, out String diffs3 ).ShouldBeTrue( customMessage: diffs3 );
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/Fill4Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | using Shouldly;
7 |
8 | using AsyncDataAdapter.Tests.FakeDb;
9 |
10 | namespace AsyncDataAdapter.Tests.Big3
11 | {
12 | public class Fill4Test : SingleMethodTest
13 | {
14 | protected override DataTable RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
15 | {
16 | DataTable dataTable = new DataTable();
17 |
18 | Int32 rowsInFirstTable = adapter.Fill4( dataTable: dataTable );
19 | rowsInFirstTable.ShouldBe( 40 );
20 |
21 | return dataTable;
22 | }
23 |
24 | protected override DataTable RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
25 | {
26 | DataTable dataTable = new DataTable();
27 |
28 | Int32 rowsInFirstTable = adapter.Fill4( dataTable: dataTable );
29 | rowsInFirstTable.ShouldBe( 40 );
30 |
31 | return dataTable;
32 | }
33 |
34 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
35 | {
36 | DataTable dataTable = new DataTable();
37 |
38 | Int32 rowsInFirstTable = await adapter.Fill4Async( dataTable: dataTable );
39 | rowsInFirstTable.ShouldBe( 40 );
40 |
41 | return dataTable;
42 | }
43 |
44 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
45 | {
46 | DataTable dataTable = new DataTable();
47 |
48 | Int32 rowsInFirstTable = await adapter.Fill4Async( dataTable );
49 | rowsInFirstTable.ShouldBe( 40 );
50 |
51 | return dataTable;
52 | }
53 |
54 | protected override void AssertResult(DataTable dbSynchronous, DataTable dbProxied, DataTable dbProxiedAsync, DataTable dbBatchingProxiedAsync)
55 | {
56 | DataTableMethods.DataTableEquals( dbSynchronous, dbProxied , "1", out String differences1 ).ShouldBeTrue( customMessage: "First different row at index: " + differences1 );
57 | DataTableMethods.DataTableEquals( dbSynchronous, dbProxiedAsync , "2", out String differences2 ).ShouldBeTrue( customMessage: "First different row at index: " + differences2 );
58 | DataTableMethods.DataTableEquals( dbSynchronous, dbBatchingProxiedAsync, "3", out String differences3 ).ShouldBeTrue( customMessage: "First different row at index: " + differences3 );
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/Fill5Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | using Shouldly;
7 |
8 | using AsyncDataAdapter.Tests.FakeDb;
9 |
10 | namespace AsyncDataAdapter.Tests.Big3
11 | {
12 | public class Fill5Test : SingleMethodTest
13 | {
14 | // When using Fill5 with DataTable[] arrays of length other-than 1, the startRecord and maxRecord values must both be zero.
15 | // See `throw ADP.OnlyOneTableForStartRecordOrMaxRecords();` in the reference-source.
16 |
17 | protected override DataTable[] RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
18 | {
19 | DataTable[] tables = new DataTable[5]
20 | {
21 | new DataTable( tableName: "Foo", tableNamespace: "NS1" ),
22 | new DataTable( tableName: "Bar", tableNamespace: "NS1" ),
23 | new DataTable( tableName: "Baz", tableNamespace: "NS1" ),
24 | new DataTable( tableName: "Qux", tableNamespace: "NS1" ),
25 | new DataTable( tableName: "Tux", tableNamespace: "NS1" )
26 | };
27 |
28 | Int32 rowsInFirstTable = adapter.Fill5( startRecord: 0, maxRecords: 0, dataTables: tables );
29 | rowsInFirstTable.ShouldBe( 40 );
30 |
31 | return tables;
32 | }
33 |
34 | protected override DataTable[] RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
35 | {
36 | DataTable[] tables = new DataTable[5]
37 | {
38 | new DataTable( tableName: "Foo", tableNamespace: "NS1" ),
39 | new DataTable( tableName: "Bar", tableNamespace: "NS1" ),
40 | new DataTable( tableName: "Baz", tableNamespace: "NS1" ),
41 | new DataTable( tableName: "Qux", tableNamespace: "NS1" ),
42 | new DataTable( tableName: "Tux", tableNamespace: "NS1" )
43 | };
44 |
45 | Int32 rowsInFirstTable = adapter.Fill5( startRecord: 0, maxRecords: 0, dataTables: tables );
46 | rowsInFirstTable.ShouldBe( 40 );
47 |
48 | return tables;
49 | }
50 |
51 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
52 | {
53 | DataTable[] tables = new DataTable[5]
54 | {
55 | new DataTable( tableName: "Foo", tableNamespace: "NS1" ),
56 | new DataTable( tableName: "Bar", tableNamespace: "NS1" ),
57 | new DataTable( tableName: "Baz", tableNamespace: "NS1" ),
58 | new DataTable( tableName: "Qux", tableNamespace: "NS1" ),
59 | new DataTable( tableName: "Tux", tableNamespace: "NS1" )
60 | };
61 |
62 | Int32 rowsInFirstTable = await adapter.Fill5Async( startRecord: 0, maxRecords: 0, dataTables: tables );
63 | rowsInFirstTable.ShouldBe( 40 );
64 |
65 | return tables;
66 | }
67 |
68 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
69 | {
70 | DataTable[] tables = new DataTable[5]
71 | {
72 | new DataTable( tableName: "Foo", tableNamespace: "NS1" ),
73 | new DataTable( tableName: "Bar", tableNamespace: "NS1" ),
74 | new DataTable( tableName: "Baz", tableNamespace: "NS1" ),
75 | new DataTable( tableName: "Qux", tableNamespace: "NS1" ),
76 | new DataTable( tableName: "Tux", tableNamespace: "NS1" )
77 | };
78 |
79 | Int32 rowsInFirstTable = await adapter.Fill5Async( startRecord: 0, maxRecords: 0, dataTables: tables );
80 | rowsInFirstTable.ShouldBe( 40 );
81 |
82 | return tables;
83 | }
84 |
85 | protected override void AssertResult(DataTable[] dbSynchronous, DataTable[] dbProxied, DataTable[] dbProxiedAsync, DataTable[] dbBatchingProxiedAsync)
86 | {
87 | DataTableMethods.DataTablesEquals( dbSynchronous, dbProxied , out String diffs1 ).ShouldBeTrue( customMessage: diffs1 );
88 | DataTableMethods.DataTablesEquals( dbSynchronous, dbProxiedAsync , out String diffs2 ).ShouldBeTrue( customMessage: diffs2 );
89 | DataTableMethods.DataTablesEquals( dbSynchronous, dbBatchingProxiedAsync, out String diffs3 ).ShouldBeTrue( customMessage: diffs3 );
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/FillSchema1Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | using Shouldly;
7 |
8 | using AsyncDataAdapter.Tests.FakeDb;
9 |
10 | namespace AsyncDataAdapter.Tests.Big3
11 | {
12 | using FS1Pair = ValueTuple;
13 |
14 | public abstract class FillSchema1Test : SingleMethodTest
15 | {
16 | protected FillSchema1Test( SchemaType schemaType )
17 | {
18 | this.SchemaType = schemaType;
19 | }
20 |
21 | protected SchemaType SchemaType { get; }
22 |
23 | protected override FS1Pair RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
24 | {
25 | DataSet dataSet = new DataSet();
26 |
27 | DataTable[] schemaTables = adapter.FillSchema1( dataSet, schemaType: this.SchemaType );
28 |
29 | return ( dataSet, schemaTables );
30 | }
31 |
32 | protected override FS1Pair RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
33 | {
34 | DataSet dataSet = new DataSet();
35 |
36 | DataTable[] schemaTables = adapter.FillSchema1( dataSet, schemaType: this.SchemaType );
37 |
38 | return ( dataSet, schemaTables );
39 | }
40 |
41 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
42 | {
43 | DataSet dataSet = new DataSet();
44 |
45 | DataTable[] schemaTables = await adapter.FillSchema1Async( dataSet, schemaType: this.SchemaType );
46 |
47 | return ( dataSet, schemaTables );
48 | }
49 |
50 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
51 | {
52 | DataSet dataSet = new DataSet();
53 |
54 | DataTable[] schemaTables = await adapter.FillSchema1Async( dataSet, schemaType: this.SchemaType );
55 |
56 | return ( dataSet, schemaTables );
57 | }
58 |
59 | protected override void AssertResult( FS1Pair dbSynchronous, FS1Pair dbProxied, FS1Pair dbProxiedAsync, FS1Pair dbBatchingProxiedAsync )
60 | {
61 | DataTableMethods.DataSetEquals( dbSynchronous.Item1, dbProxied .Item1, out String diffs11 ).ShouldBeTrue( customMessage: diffs11 );
62 | DataTableMethods.DataSetEquals( dbSynchronous.Item1, dbProxiedAsync .Item1, out String diffs12 ).ShouldBeTrue( customMessage: diffs12 );
63 | DataTableMethods.DataSetEquals( dbSynchronous.Item1, dbBatchingProxiedAsync.Item1, out String diffs13 ).ShouldBeTrue( customMessage: diffs13 );
64 |
65 | DataTableMethods.DataTablesEquals( dbSynchronous.Item2, dbProxied .Item2, out String diffs21 ).ShouldBeTrue( customMessage: diffs21 );
66 | DataTableMethods.DataTablesEquals( dbSynchronous.Item2, dbProxiedAsync .Item2, out String diffs22 ).ShouldBeTrue( customMessage: diffs22 );
67 | DataTableMethods.DataTablesEquals( dbSynchronous.Item2, dbBatchingProxiedAsync.Item2, out String diffs23 ).ShouldBeTrue( customMessage: diffs23 );
68 | }
69 | }
70 |
71 | public class FillSchema1MappedTest : FillSchema1Test
72 | {
73 | public FillSchema1MappedTest()
74 | : base( SchemaType.Mapped )
75 | {
76 | }
77 | }
78 |
79 | public class FillSchema1SourceTest : FillSchema1Test
80 | {
81 | public FillSchema1SourceTest()
82 | : base( SchemaType.Source )
83 | {
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/FillSchema2Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | using Shouldly;
7 |
8 | using AsyncDataAdapter.Tests.FakeDb;
9 |
10 | namespace AsyncDataAdapter.Tests.Big3
11 | {
12 | using FS2Pair = ValueTuple;
13 |
14 | public abstract class FillSchema2Test : SingleMethodTest
15 | {
16 | protected FillSchema2Test( SchemaType schemaType )
17 | {
18 | this.SchemaType = schemaType;
19 | }
20 |
21 | protected SchemaType SchemaType { get; }
22 |
23 | protected override FS2Pair RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
24 | {
25 | DataTable dataTable = new DataTable();
26 |
27 | DataTable schemaTables = adapter.FillSchema2( dataTable, schemaType: this.SchemaType );
28 |
29 | return ( dataTable, schemaTables );
30 | }
31 |
32 | protected override FS2Pair RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
33 | {
34 | DataTable dataTable = new DataTable();
35 |
36 | DataTable schemaTables = adapter.FillSchema2( dataTable, schemaType: this.SchemaType );
37 |
38 | return ( dataTable, schemaTables );
39 | }
40 |
41 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
42 | {
43 | DataTable dataTable = new DataTable();
44 |
45 | DataTable schemaTables = await adapter.FillSchema2Async( dataTable, schemaType: this.SchemaType );
46 |
47 | return ( dataTable, schemaTables );
48 | }
49 |
50 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
51 | {
52 | DataTable dataTable = new DataTable();
53 |
54 | DataTable schemaTables = await adapter.FillSchema2Async( dataTable, schemaType: this.SchemaType );
55 |
56 | return ( dataTable, schemaTables );
57 | }
58 |
59 | protected override void AssertResult( FS2Pair dbSynchronous, FS2Pair dbProxied, FS2Pair dbProxiedAsync, FS2Pair dbBatchingProxiedAsync )
60 | {
61 | DataTableMethods.DataTableEquals( dbSynchronous.Item1, dbProxied .Item1, "1", out String diffs11 ).ShouldBeTrue( customMessage: diffs11 );
62 | DataTableMethods.DataTableEquals( dbSynchronous.Item1, dbProxiedAsync .Item1, "2", out String diffs12 ).ShouldBeTrue( customMessage: diffs12 );
63 | DataTableMethods.DataTableEquals( dbSynchronous.Item1, dbBatchingProxiedAsync.Item1, "3", out String diffs13 ).ShouldBeTrue( customMessage: diffs13 );
64 |
65 | DataTableMethods.DataTableEquals( dbSynchronous.Item2, dbProxied .Item2, "1", out String diffs21 ).ShouldBeTrue( customMessage: diffs21 );
66 | DataTableMethods.DataTableEquals( dbSynchronous.Item2, dbProxiedAsync .Item2, "2", out String diffs22 ).ShouldBeTrue( customMessage: diffs22 );
67 | DataTableMethods.DataTableEquals( dbSynchronous.Item2, dbBatchingProxiedAsync.Item2, "3", out String diffs23 ).ShouldBeTrue( customMessage: diffs23 );
68 | }
69 | }
70 |
71 | public class FillSchema2MappedTest : FillSchema2Test
72 | {
73 | public FillSchema2MappedTest()
74 | : base( SchemaType.Mapped )
75 | {
76 | }
77 | }
78 |
79 | public class FillSchema2SourceTest : FillSchema2Test
80 | {
81 | public FillSchema2SourceTest()
82 | : base( SchemaType.Source )
83 | {
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/FillSchema3Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | using Shouldly;
7 |
8 | using AsyncDataAdapter.Tests.FakeDb;
9 |
10 | namespace AsyncDataAdapter.Tests.Big3
11 | {
12 | using FS3Pair = ValueTuple;
13 |
14 | public abstract class FillSchema3Test : SingleMethodTest
15 | {
16 | protected FillSchema3Test( SchemaType schemaType )
17 | {
18 | this.SchemaType = schemaType;
19 | }
20 |
21 | protected SchemaType SchemaType { get; }
22 |
23 | protected override FS3Pair RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
24 | {
25 | DataSet dataSet = new DataSet();
26 |
27 | DataTable[] schemaTables = adapter.FillSchema3( dataSet, schemaType: this.SchemaType, srcTable: "Foobar" );
28 |
29 | return ( dataSet, schemaTables );
30 | }
31 |
32 | protected override FS3Pair RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
33 | {
34 | DataSet dataSet = new DataSet();
35 |
36 | DataTable[] schemaTables = adapter.FillSchema3( dataSet, schemaType: this.SchemaType, srcTable: "Foobar" );
37 |
38 | return ( dataSet, schemaTables );
39 | }
40 |
41 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
42 | {
43 | DataSet dataSet = new DataSet();
44 |
45 | DataTable[] schemaTables = await adapter.FillSchema3Async( dataSet, schemaType: this.SchemaType, srcTable: "Foobar" );
46 |
47 | return ( dataSet, schemaTables );
48 | }
49 |
50 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
51 | {
52 | DataSet dataSet = new DataSet();
53 |
54 | DataTable[] schemaTables = await adapter.FillSchema3Async( dataSet, schemaType: this.SchemaType, srcTable: "Foobar" );
55 |
56 | return ( dataSet, schemaTables );
57 | }
58 |
59 | protected override void AssertResult( FS3Pair dbSynchronous, FS3Pair dbProxied, FS3Pair dbProxiedAsync, FS3Pair dbBatchingProxiedAsync )
60 | {
61 | DataTableMethods.DataSetEquals( dbSynchronous.Item1, dbProxied .Item1, out String diffs11 ).ShouldBeTrue( customMessage: diffs11 );
62 | DataTableMethods.DataSetEquals( dbSynchronous.Item1, dbProxiedAsync .Item1, out String diffs12 ).ShouldBeTrue( customMessage: diffs12 );
63 | DataTableMethods.DataSetEquals( dbSynchronous.Item1, dbBatchingProxiedAsync.Item1, out String diffs13 ).ShouldBeTrue( customMessage: diffs13 );
64 |
65 | DataTableMethods.DataTablesEquals( dbSynchronous.Item2, dbProxied .Item2, out String diffs21 ).ShouldBeTrue( customMessage: diffs21 );
66 | DataTableMethods.DataTablesEquals( dbSynchronous.Item2, dbProxiedAsync .Item2, out String diffs22 ).ShouldBeTrue( customMessage: diffs22 );
67 | DataTableMethods.DataTablesEquals( dbSynchronous.Item2, dbBatchingProxiedAsync.Item2, out String diffs23 ).ShouldBeTrue( customMessage: diffs23 );
68 | }
69 | }
70 |
71 | public class FillSchema3MappedTest : FillSchema3Test
72 | {
73 | public FillSchema3MappedTest()
74 | : base( SchemaType.Mapped )
75 | {
76 | }
77 | }
78 |
79 | public class FillSchema3SourceTest : FillSchema3Test
80 | {
81 | public FillSchema3SourceTest()
82 | : base( SchemaType.Source )
83 | {
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/Update2Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data;
4 | using System.Data.Common;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | using Shouldly;
9 |
10 | using AsyncDataAdapter.Tests.FakeDb;
11 |
12 | namespace AsyncDataAdapter.Tests.Big3
13 | {
14 | using U2Pair = ValueTuple,Int32>;
15 |
16 | public class Update2Test : SingleMethodTest
17 | {
18 | protected override U2Pair RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
19 | {
20 | using( FakeDbCommandBuilder cmdBuilder = adapter.CreateCommandBuilder() )
21 | {
22 | DataTable dataTable = new DataTable();
23 |
24 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
25 | Int32 rowsInFirstTable = adapter.Fill( dataTable );
26 | rowsInFirstTable.ShouldBe( 40 );
27 |
28 | //
29 | Dictionary rowsModified = DataTableMethods.MutateDataTable( dataTable );
30 |
31 | //
32 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
33 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataTable, cmd, rowsModified );
34 |
35 | DataRow[] rows = dataTable.Rows.Cast().ToArray();
36 |
37 | Int32 updatedRows = adapter.Update2( rows );
38 | // updatedRows.ShouldBe( rowsModified );
39 |
40 | return ( rows, rowsModified, updatedRows );
41 | }
42 | }
43 |
44 | protected override U2Pair RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
45 | {
46 | using( FakeDbCommandBuilder cmdBuilder = new FakeDbCommandBuilder( adapter ) )
47 | {
48 | DataTable dataTable = new DataTable();
49 |
50 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
51 | Int32 rowsInFirstTable = adapter.Fill( dataTable );
52 | rowsInFirstTable.ShouldBe( 40 );
53 |
54 | //
55 | Dictionary rowsModified = DataTableMethods.MutateDataTable( dataTable );
56 |
57 | //
58 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
59 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataTable, cmd, rowsModified );
60 |
61 | DataRow[] rows = dataTable.Rows.Cast().ToArray();
62 |
63 | Int32 updatedRows = adapter.Update2( rows );
64 | // updatedRows.ShouldBe( rowsModified );
65 |
66 | return ( rows, rowsModified, updatedRows );
67 | }
68 | }
69 |
70 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
71 | {
72 | using( DbCommandBuilder cmdBuilder = await adapter.CreateCommandBuilderAsync().ConfigureAwait(false) )
73 | {
74 | DataTable dataTable = new DataTable();
75 |
76 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
77 | Int32 rowsInFirstTable = await adapter.FillAsync( dataTable );
78 | rowsInFirstTable.ShouldBe( 40 );
79 |
80 | //
81 | Dictionary rowsModified = DataTableMethods.MutateDataTable( dataTable );
82 |
83 | //
84 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
85 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataTable, cmd, rowsModified );
86 |
87 | DataRow[] rows = dataTable.Rows.Cast().ToArray();
88 |
89 | Int32 updatedRows = await adapter.Update2Async( rows );
90 | // updatedRows.ShouldBe( rowsModified );
91 |
92 | return ( rows, rowsModified, updatedRows );
93 | }
94 | }
95 |
96 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
97 | {
98 | using( DbCommandBuilder cmdBuilder = await adapter.CreateCommandBuilderAsync().ConfigureAwait(false) )
99 | {
100 | DataTable dataTable = new DataTable();
101 |
102 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
103 | Int32 rowsInFirstTable = adapter.Fill( dataTable );
104 | rowsInFirstTable.ShouldBe( 40 );
105 |
106 | //
107 | Dictionary rowsModified = DataTableMethods.MutateDataTable( dataTable );
108 |
109 | //
110 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
111 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataTable, cmd, rowsModified );
112 |
113 | DataRow[] rows = dataTable.Rows.Cast().ToArray();
114 |
115 | Int32 updatedRows = await adapter.Update2Async( rows );
116 | // updatedRows.ShouldBe( rowsModified );
117 |
118 | return ( rows, rowsModified, updatedRows );
119 | }
120 | }
121 |
122 | protected override void AssertResult( U2Pair dbSynchronous, U2Pair dbProxied, U2Pair dbProxiedAsync, U2Pair dbBatchingProxiedAsync )
123 | {
124 | throw new NotImplementedException();
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/Update3Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data;
4 | using System.Data.Common;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | using Shouldly;
9 |
10 | using AsyncDataAdapter.Tests.FakeDb;
11 |
12 | namespace AsyncDataAdapter.Tests.Big3
13 | {
14 | using U3Pair = ValueTuple,Int32>;
15 |
16 | public class Update3Test : SingleMethodTest
17 | {
18 | protected override U3Pair RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
19 | {
20 | using( FakeDbCommandBuilder cmdBuilder = adapter.CreateCommandBuilder() )
21 | {
22 | DataTable dataTable = new DataTable();
23 |
24 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
25 | Int32 rowsInFirstTable = adapter.Fill( dataTable );
26 | rowsInFirstTable.ShouldBe( 40 );
27 |
28 | //
29 | Dictionary rowsModified = DataTableMethods.MutateDataTable( dataTable );
30 |
31 | //
32 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
33 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataTable, cmd, rowsModified );
34 |
35 | Int32 updatedRows = adapter.Update3( dataTable );
36 | // updatedRows.ShouldBe( rowsModified );
37 |
38 | return ( dataTable, rowsModified, updatedRows );
39 | }
40 | }
41 |
42 | protected override U3Pair RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
43 | {
44 | using( FakeDbCommandBuilder cmdBuilder = new FakeDbCommandBuilder( adapter ) )
45 | {
46 | DataTable dataTable = new DataTable();
47 |
48 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
49 | Int32 rowsInFirstTable = adapter.Fill( dataTable );
50 | rowsInFirstTable.ShouldBe( 40 );
51 |
52 | //
53 | Dictionary rowsModified = DataTableMethods.MutateDataTable( dataTable );
54 |
55 | //
56 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
57 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataTable, cmd, rowsModified );
58 |
59 | Int32 updatedRows = adapter.Update3( dataTable );
60 | // updatedRows.ShouldBe( rowsModified );
61 |
62 | return ( dataTable, rowsModified, updatedRows );
63 | }
64 | }
65 |
66 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
67 | {
68 | using( DbCommandBuilder cmdBuilder = await adapter.CreateCommandBuilderAsync().ConfigureAwait(false) )
69 | {
70 | DataTable dataTable = new DataTable();
71 |
72 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
73 | Int32 rowsInFirstTable = await adapter.FillAsync( dataTable );
74 | rowsInFirstTable.ShouldBe( 40 );
75 |
76 | //
77 | Dictionary rowsModified = DataTableMethods.MutateDataTable( dataTable );
78 |
79 | //
80 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
81 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataTable, cmd, rowsModified );
82 |
83 | Int32 updatedRows = await adapter.Update3Async( dataTable );
84 | // updatedRows.ShouldBe( rowsModified );
85 |
86 | return ( dataTable, rowsModified, updatedRows );
87 | }
88 | }
89 |
90 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
91 | {
92 | using( DbCommandBuilder cmdBuilder = await adapter.CreateCommandBuilderAsync().ConfigureAwait(false) )
93 | {
94 | DataTable dataTable = new DataTable();
95 |
96 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
97 | Int32 rowsInFirstTable = adapter.Fill( dataTable );
98 | rowsInFirstTable.ShouldBe( 40 );
99 |
100 | //
101 | Dictionary rowsModified = DataTableMethods.MutateDataTable( dataTable );
102 |
103 | //
104 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
105 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataTable, cmd, rowsModified );
106 |
107 | DataRow[] rows = dataTable.Rows.Cast().ToArray();
108 |
109 | Int32 updatedRows = await adapter.Update3Async( dataTable );
110 | // updatedRows.ShouldBe( rowsModified );
111 |
112 | return ( dataTable, rowsModified, updatedRows );
113 | }
114 | }
115 |
116 | protected override void AssertResult( U3Pair dbSynchronous, U3Pair dbProxied, U3Pair dbProxiedAsync, U3Pair dbBatchingProxiedAsync )
117 | {
118 | throw new NotImplementedException();
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/Update4Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data;
4 | using System.Data.Common;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | using Shouldly;
9 |
10 | using AsyncDataAdapter.Tests.FakeDb;
11 |
12 | namespace AsyncDataAdapter.Tests.Big3
13 | {
14 | using U4Pair = ValueTuple,Int32>;
15 |
16 | public class Update4Test : SingleMethodTest
17 | {
18 | protected override U4Pair RunDbDataAdapterSynchronous(List randomDataSource, FakeDbDataAdapter adapter)
19 | {
20 | using( FakeDbCommandBuilder cmdBuilder = adapter.CreateCommandBuilder() )
21 | {
22 | DataSet dataSet = new DataSet();
23 |
24 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
25 | Int32 rowsInFirstTable = adapter.Fill( dataSet );
26 | rowsInFirstTable.ShouldBe( 40 );
27 |
28 | //
29 | Dictionary rowsModified = DataTableMethods.MutateDataSet( dataSet );
30 |
31 | //
32 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
33 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataSet, cmd, rowsModified );
34 |
35 | Int32 updatedRows = adapter.Update4( dataSet, srcTable: "RandomDataTable_2" );
36 | // updatedRows.ShouldBe( rowsModified );
37 |
38 | return ( dataSet, rowsModified, updatedRows );
39 | }
40 | }
41 |
42 | protected override U4Pair RunProxiedDbDataAdapter(List randomDataSource, FakeProxiedDbDataAdapter adapter)
43 | {
44 | using( FakeDbCommandBuilder cmdBuilder = new FakeDbCommandBuilder( adapter ) )
45 | {
46 | DataSet dataSet = new DataSet();
47 |
48 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
49 | Int32 rowsInFirstTable = adapter.Fill( dataSet );
50 | rowsInFirstTable.ShouldBe( 40 );
51 |
52 | //
53 | Dictionary rowsModified = DataTableMethods.MutateDataSet( dataSet );
54 |
55 | //
56 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
57 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataSet, cmd, rowsModified );
58 |
59 | Int32 updatedRows = adapter.Update4( dataSet, srcTable: "RandomDataTable_2" );
60 | // updatedRows.ShouldBe( rowsModified );
61 |
62 | return ( dataSet, rowsModified, updatedRows );
63 | }
64 | }
65 |
66 | protected override async Task RunProxiedDbDataAdapterAsync(List randomDataSource, FakeProxiedDbDataAdapter adapter)
67 | {
68 | using( DbCommandBuilder cmdBuilder = await adapter.CreateCommandBuilderAsync().ConfigureAwait(false) )
69 | {
70 | DataSet dataSet = new DataSet();
71 |
72 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
73 | Int32 rowsInFirstTable = await adapter.FillAsync( dataSet );
74 | rowsInFirstTable.ShouldBe( 40 );
75 |
76 | //
77 | Dictionary rowsModified = DataTableMethods.MutateDataSet( dataSet );
78 |
79 | //
80 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
81 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataSet, cmd, rowsModified );
82 |
83 | Int32 updatedRows = await adapter.Update4Async( dataSet, srcTable: "RandomDataTable_2" );
84 | // updatedRows.ShouldBe( rowsModified );
85 |
86 | return ( dataSet, rowsModified, updatedRows );
87 | }
88 | }
89 |
90 | protected override async Task RunBatchingProxiedDbDataAdapterAsync(List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter)
91 | {
92 | using( DbCommandBuilder cmdBuilder = await adapter.CreateCommandBuilderAsync().ConfigureAwait(false) )
93 | {
94 | DataSet dataSet = new DataSet();
95 |
96 | // `.Fill` returns the number of rows in the first table, not any subsequent tables. Yes, that's silly.
97 | Int32 rowsInFirstTable = adapter.Fill( dataSet );
98 | rowsInFirstTable.ShouldBe( 40 );
99 |
100 | //
101 | Dictionary rowsModified = DataTableMethods.MutateDataSet( dataSet );
102 |
103 | //
104 | adapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
105 | adapter.UpdateCommand.NonQueryResultRowCountValue = ( cmd ) => DataTableMethods.GetUpdateStatementNonQueryResultRowCountValue( expectedTableName: "TODO", adapter, dataSet, cmd, rowsModified );
106 |
107 | Int32 updatedRows = await adapter.Update4Async( dataSet, srcTable: "RandomDataTable_2" );
108 | // updatedRows.ShouldBe( rowsModified );
109 |
110 | return ( dataSet, rowsModified, updatedRows );
111 | }
112 | }
113 |
114 | protected override void AssertResult( U4Pair dbSynchronous, U4Pair dbProxied, U4Pair dbProxiedAsync, U4Pair dbBatchingProxiedAsync )
115 | {
116 | throw new NotImplementedException();
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SingleMethodTests/Utility/SingleMethodTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | using AsyncDataAdapter.Tests.FakeDb;
6 |
7 | using NUnit.Framework;
8 |
9 | namespace AsyncDataAdapter.Tests.Big3
10 | {
11 | public abstract class SingleMethodTest
12 | {
13 | protected abstract TResult RunDbDataAdapterSynchronous( List randomDataSource, FakeDbDataAdapter adapter );
14 |
15 | protected abstract TResult RunProxiedDbDataAdapter( List randomDataSource, FakeProxiedDbDataAdapter adapter );
16 |
17 | protected abstract Task RunProxiedDbDataAdapterAsync( List randomDataSource, FakeProxiedDbDataAdapter adapter );
18 |
19 | protected abstract Task RunBatchingProxiedDbDataAdapterAsync( List randomDataSource, BatchingFakeProxiedDbDataAdapter adapter );
20 |
21 | protected abstract void AssertResult( TResult dbSynchronous, TResult dbProxied, TResult dbProxiedAsync, TResult dbBatchingProxiedAsync );
22 |
23 | //
24 |
25 | [Test]
26 | public virtual async Task Test_with_single_table()
27 | {
28 | await this.RunAsync( seed: 1234, tableCount: 1 );
29 | }
30 |
31 | [Test]
32 | public virtual async Task Test_with_five_tables()
33 | {
34 | await this.RunAsync( seed: 1234, tableCount: 5 );
35 | }
36 |
37 | protected async Task RunAsync( Int32 seed, Int32 tableCount )
38 | {
39 | TResult dbSynchronous = this.DoRunDbDataAdapterSynchronous( seed, tableCount );
40 |
41 | TResult dbProxied = this.DoRunProxiedDbDataAdapter( seed, tableCount );
42 |
43 | TResult dbProxiedAsync = await this.DoRunProxiedDbDataAdapterAsync( seed, tableCount );
44 |
45 | TResult dbBatchingProxiedAsync = await this.DoRunBatchingProxiedDbDataAdapterAsync( seed, tableCount );
46 |
47 | //
48 |
49 | this.AssertResult( dbSynchronous, dbProxied, dbProxiedAsync, dbBatchingProxiedAsync );
50 | }
51 |
52 | protected TResult DoRunDbDataAdapterSynchronous( Int32 seed, Int32 tableCount )
53 | {
54 | List randomDataSource = RandomDataGenerator.CreateRandomTables( seed: seed, tableCount: tableCount );
55 |
56 | using( FakeDbConnection connection = new FakeDbConnection( asyncMode: AsyncMode.AllowSync ) )
57 | using( FakeDbCommand selectCommand = connection.CreateCommand( testTables: randomDataSource ) )
58 | {
59 | connection.Open();
60 |
61 | using( FakeDbDataAdapter adapter = new FakeDbDataAdapter( selectCommand ) )
62 | {
63 | return this.RunDbDataAdapterSynchronous( randomDataSource, adapter );
64 | }
65 | }
66 | }
67 |
68 | protected TResult DoRunProxiedDbDataAdapter( Int32 seed, Int32 tableCount )
69 | {
70 | List randomDataSource = RandomDataGenerator.CreateRandomTables( seed: seed, tableCount: tableCount );
71 |
72 | using( FakeDbConnection connection = new FakeDbConnection( asyncMode: AsyncMode.AllowSync ) )
73 | using( FakeDbCommand selectCommand = connection.CreateCommand( testTables: randomDataSource ) )
74 | {
75 | connection.Open();
76 |
77 | using( FakeProxiedDbDataAdapter adapter = new FakeProxiedDbDataAdapter( selectCommand ) )
78 | {
79 | return this.RunProxiedDbDataAdapter( randomDataSource, adapter );
80 | }
81 | }
82 | }
83 |
84 | protected async Task DoRunProxiedDbDataAdapterAsync( Int32 seed, Int32 tableCount )
85 | {
86 | List randomDataSource = RandomDataGenerator.CreateRandomTables( seed: seed, tableCount: tableCount );
87 |
88 | using( FakeDbConnection connection = new FakeDbConnection( asyncMode: AsyncMode.AwaitAsync ) )
89 | using( FakeDbCommand selectCommand = connection.CreateCommand( testTables: randomDataSource ) )
90 | {
91 | await connection.OpenAsync();
92 |
93 | using( FakeProxiedDbDataAdapter adapter = new FakeProxiedDbDataAdapter( selectCommand ) )
94 | {
95 | return await this.RunProxiedDbDataAdapterAsync( randomDataSource, adapter );
96 | }
97 | }
98 | }
99 |
100 | protected async Task DoRunBatchingProxiedDbDataAdapterAsync( Int32 seed, Int32 tableCount )
101 | {
102 | List randomDataSource = RandomDataGenerator.CreateRandomTables( seed: seed, tableCount: tableCount );
103 |
104 | using( FakeDbConnection connection = new FakeDbConnection( asyncMode: AsyncMode.AwaitAsync ) )
105 | using( FakeDbCommand selectCommand = connection.CreateCommand( testTables: randomDataSource ) )
106 | {
107 | await connection.OpenAsync();
108 |
109 | using( BatchingFakeProxiedDbDataAdapter adapter = new BatchingFakeProxiedDbDataAdapter( selectCommand ) )
110 | {
111 | return await this.RunBatchingProxiedDbDataAdapterAsync( randomDataSource, adapter );
112 | }
113 | }
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SqlServer/MicrosoftDataSqlTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Common;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | using Microsoft.Data.SqlClient;
8 |
9 | namespace AsyncDataAdapter.Tests.SqlServer
10 | {
11 | public class MicrosoftDataSqlTests : BaseSqlDataAdapterTest
12 | {
13 | protected override SqlConnection CreateConnection( String connectionString )
14 | {
15 | return new SqlConnection( connectionString );
16 | }
17 |
18 | protected override SqlCommand CreateCommand(SqlConnection connection)
19 | {
20 | return connection.CreateCommand();
21 | }
22 |
23 | protected override SqlDataAdapter CreateDbAdapter( SqlCommand cmd )
24 | {
25 | return new SqlDataAdapter( cmd );
26 | }
27 |
28 | protected override MSSqlAsyncDbDataAdapter CreateAsyncDbAdapter( SqlCommand cmd )
29 | {
30 | return new MSSqlAsyncDbDataAdapter( cmd );
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/SqlServer/SystemDataSqlTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Common;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | using System.Data.SqlClient;
8 |
9 | namespace AsyncDataAdapter.Tests.SqlServer
10 | {
11 | public class SystemDataSqlTests : BaseSqlDataAdapterTest
12 | {
13 | protected override SqlConnection CreateConnection( String connectionString )
14 | {
15 | return new SqlConnection( connectionString );
16 | }
17 |
18 | protected override SqlCommand CreateCommand( SqlConnection connection )
19 | {
20 | return connection.CreateCommand();
21 | }
22 |
23 | protected override SqlDataAdapter CreateDbAdapter( SqlCommand cmd )
24 | {
25 | return new SqlDataAdapter( cmd );
26 | }
27 |
28 | protected override SqlAsyncDbDataAdapter CreateAsyncDbAdapter( SqlCommand cmd )
29 | {
30 | return new SqlAsyncDbDataAdapter( cmd );
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/TestConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | using Microsoft.Extensions.Configuration;
5 |
6 | namespace AsyncDataAdapter.Tests
7 | {
8 | public class TestConfiguration
9 | {
10 | // private const string _defaultConnectionString = @"server=.\sqlexpress;database=AsyncDataReaderTest;Trusted_Connection=Yes";
11 | private const string _defaultConnectionString = @"server=.\SQL2017;database=AsyncDataReaderTest;Trusted_Connection=Yes";
12 |
13 | public static TestConfiguration Instance { get; } = new TestConfiguration();
14 |
15 | /// See https://stackoverflow.com/questions/39791634/read-appsettings-json-values-in-net-core-test-project/47591692
16 | private TestConfiguration()
17 | {
18 | const string fileName = "test-config.json";
19 | if( File.Exists( fileName ))
20 | {
21 | IConfigurationRoot config = new ConfigurationBuilder()
22 | .AddJsonFile( fileName )
23 | .Build();
24 |
25 | this.ConnectionString = config["ConnectionString"];
26 | #pragma warning disable IDE0075 // Simplify conditional expression
27 | this.DatabaseTestsEnabled = Boolean.TryParse( config["DatabaseTestsEnabed"], out Boolean b ) ? b : true;
28 | #pragma warning restore
29 | }
30 |
31 | if( string.IsNullOrWhiteSpace(this.ConnectionString) )
32 | {
33 | this.ConnectionString = _defaultConnectionString;
34 | }
35 | }
36 |
37 | public Boolean DatabaseTestsEnabled { get; }
38 | public String ConnectionString { get; }
39 |
40 | /* Sample appconfig json (note the '\' is escaped!):
41 |
42 | {
43 | "ConnectionString": "server=.\\SQL2017;database=AsyncDataReaderTest;Trusted_Connection=Yes"
44 | }
45 |
46 | */
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/TestUtility/FakeDbCommandBuilderTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | using AsyncDataAdapter.Tests.FakeDb;
4 |
5 | using NUnit.Framework;
6 |
7 | using Shouldly;
8 |
9 | namespace AsyncDataAdapter.Tests.MetaTests
10 | {
11 | /// Just some meta-tests so I know my class works.
12 | public class FakeDbCommandBuilderTests
13 | {
14 | [Test]
15 | public void FakeDbCommandBuilder_should_work()
16 | {
17 | List randomDataSource = RandomDataGenerator.CreateRandomTables( seed: 1234, tableCount: 5, /*allowZeroRowsInTablesByIdx: */ 1, 3 );
18 |
19 | using( FakeDbConnection connection = new FakeDbConnection( asyncMode: AsyncMode.AllowSync ) )
20 | using( FakeDbCommand selectCommand = connection.CreateCommand( testTables: randomDataSource ) )
21 | {
22 | connection.Open();
23 |
24 | using( FakeDbDataAdapter adpt = new FakeDbDataAdapter( selectCommand ) )
25 | using( FakeDbCommandBuilder cmdBuilder = adpt.CreateCommandBuilder() )
26 | {
27 | cmdBuilder.DataAdapter.ShouldBe( adpt );
28 |
29 | FakeDbCommand deleteCommand1 = cmdBuilder.GetDeleteCommand(); // Same as ` useColumnsForParameterNames: false );`
30 | FakeDbCommand updateCommand1 = cmdBuilder.GetUpdateCommand();
31 | FakeDbCommand insertCommand1 = cmdBuilder.GetInsertCommand();
32 |
33 | FakeDbCommand deleteCommand2 = cmdBuilder.GetDeleteCommand( useColumnsForParameterNames: true );
34 | FakeDbCommand updateCommand2 = cmdBuilder.GetUpdateCommand( useColumnsForParameterNames: true );
35 | FakeDbCommand insertCommand2 = cmdBuilder.GetInsertCommand( useColumnsForParameterNames: true );
36 |
37 | _ = deleteCommand1.ShouldNotBeNull();
38 | _ = updateCommand1.ShouldNotBeNull();
39 | _ = insertCommand1.ShouldNotBeNull();
40 |
41 | _ = deleteCommand2.ShouldNotBeNull();
42 | _ = updateCommand2.ShouldNotBeNull();
43 | _ = insertCommand2.ShouldNotBeNull();
44 | }
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/TestUtility/FakeDbDataReaderTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | using NUnit.Framework;
6 |
7 | using Shouldly;
8 |
9 | using AsyncDataAdapter.Tests.FakeDb;
10 |
11 | namespace AsyncDataAdapter.Tests.MetaTests
12 | {
13 | /// Just some meta-tests so I know my class works.
14 | public class FakeDbDataReaderTests
15 | {
16 | [Test]
17 | public void FakeDbDataReader_Sync_should_behave()
18 | {
19 | FakeDbCommand cmd = new FakeDbCommand();
20 |
21 | FakeDbDataReader rdr = new FakeDbDataReader( cmd );
22 |
23 | List tables = RandomDataGenerator.CreateRandomTables( seed: 1234, tableCount: 5 );
24 |
25 | rdr.ResetAndLoadTestData( tables );
26 |
27 | rdr.AllTables.Count.ShouldBe( 5 );
28 | // The RNG is rather fickle, so don't test these. See the `RandomDataGenerator_seed_values_should_produce_expected_results` test above instead.
29 | // rdr.AllTables[0].Rows.Count.ShouldBe( 40 );
30 | // rdr.AllTables[1].Rows.Count.ShouldBe( 52 );
31 | // rdr.AllTables[2].Rows.Count.ShouldBe( 79 );
32 | // rdr.AllTables[3].Rows.Count.ShouldBe( 37 );
33 | // rdr.AllTables[4].Rows.Count.ShouldBe( 31 );
34 |
35 | //
36 |
37 | rdr.AsyncMode = AsyncMode.AllowSync;
38 |
39 | // Table 0:
40 | {
41 | Int32 i = 0;
42 | while( rdr.Read() )
43 | {
44 | i++;
45 | }
46 |
47 | i.ShouldBe( tables[0].Rows.Count );
48 | }
49 |
50 | // Table 1:
51 | rdr.NextResult().ShouldBeTrue();
52 | {
53 | Int32 i = 0;
54 | while( rdr.Read() )
55 | {
56 | i++;
57 | }
58 |
59 | i.ShouldBe( tables[1].Rows.Count );
60 | }
61 |
62 | // Table 2:
63 | rdr.NextResult().ShouldBeTrue();
64 | {
65 | Int32 i = 0;
66 | while( rdr.Read() )
67 | {
68 | i++;
69 | }
70 |
71 | i.ShouldBe( tables[2].Rows.Count );
72 | }
73 |
74 | // Table 3:
75 | rdr.NextResult().ShouldBeTrue();
76 | {
77 | Int32 i = 0;
78 | while( rdr.Read() )
79 | {
80 | i++;
81 | }
82 |
83 | i.ShouldBe( tables[3].Rows.Count );
84 | }
85 |
86 | // Table 4:
87 | rdr.NextResult().ShouldBeTrue();
88 | {
89 | Int32 i = 0;
90 | while( rdr.Read() )
91 | {
92 | i++;
93 | }
94 |
95 | i.ShouldBe( tables[4].Rows.Count );
96 | }
97 |
98 | rdr.NextResult().ShouldBeFalse();
99 | }
100 |
101 | [Test]
102 | public async Task FakeDbDataReader_Async_should_behave()
103 | {
104 | FakeDbCommand cmd = new FakeDbCommand();
105 |
106 | FakeDbDataReader rdr = new FakeDbDataReader( cmd );
107 |
108 | //
109 |
110 | List tables = RandomDataGenerator.CreateRandomTables( seed: 1234, tableCount: 5 );
111 |
112 | rdr.ResetAndLoadTestData( tables );
113 |
114 | rdr.AllTables.Count.ShouldBe( 5 );
115 |
116 | //
117 |
118 | rdr.AsyncMode = AsyncMode.AwaitAsync;
119 |
120 | // Table 0:
121 | {
122 | Int32 i = 0;
123 | while( await rdr.ReadAsync() )
124 | {
125 | i++;
126 | }
127 |
128 | i.ShouldBe( tables[0].Rows.Count );
129 | }
130 |
131 | // Table 1:
132 | ( await rdr.NextResultAsync() ).ShouldBeTrue();
133 | {
134 | Int32 i = 0;
135 | while( await rdr.ReadAsync() )
136 | {
137 | i++;
138 | }
139 |
140 | i.ShouldBe( tables[1].Rows.Count );
141 | }
142 |
143 | // Table 2:
144 | ( await rdr.NextResultAsync() ).ShouldBeTrue();
145 | {
146 | Int32 i = 0;
147 | while( await rdr.ReadAsync() )
148 | {
149 | i++;
150 | }
151 |
152 | i.ShouldBe( tables[2].Rows.Count );
153 | }
154 |
155 | // Table 3:
156 | ( await rdr.NextResultAsync() ).ShouldBeTrue();
157 | {
158 | Int32 i = 0;
159 | while( await rdr.ReadAsync() )
160 | {
161 | i++;
162 | }
163 |
164 | i.ShouldBe( tables[3].Rows.Count );
165 | }
166 |
167 | // Table 4:
168 | ( await rdr.NextResultAsync() ).ShouldBeTrue();
169 | {
170 | Int32 i = 0;
171 | while( await rdr.ReadAsync() )
172 | {
173 | i++;
174 | }
175 |
176 | i.ShouldBe( tables[4].Rows.Count );
177 | }
178 |
179 | ( await rdr.NextResultAsync() ).ShouldBeFalse();
180 | }
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/TestUtility/RandomDataGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using NUnit.Framework;
5 |
6 | using Shouldly;
7 |
8 | namespace AsyncDataAdapter.Tests.MetaTests
9 | {
10 | /// Just some meta-tests so I know my class works.
11 | public class RandomDataGeneratorTests
12 | {
13 | [Test]
14 | [TestCase( new Object[] { /*seed:*/ 1234, /*table row counts: */ new Int32[] { 40, 68, 35, 65, 76 } } )]
15 | public void RandomDataGenerator_seed_values_should_produce_expected_results( Int32 seed, Int32[] rowCounts )
16 | {
17 | List tables = RandomDataGenerator.CreateRandomTables( seed: seed, tableCount: rowCounts.Length );
18 |
19 | tables.Count.ShouldBe( rowCounts.Length );
20 |
21 | for( Int32 i = 0; i < rowCounts.Length; i++ )
22 | {
23 | tables[i].Rows.Count.ShouldBe( rowCounts[i] );
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/AsyncDataAdapter.Tests/TestUtility/TestTable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data;
4 |
5 | namespace AsyncDataAdapter.Tests
6 | {
7 | public class TestTable
8 | {
9 | public TestTable( int index, string name, string[] columnNames, Type[] columnTypes, List