Skip to content

Commit f4c6433

Browse files
committed
better SqlAuthenticationMethod
1 parent 5de1eeb commit f4c6433

7 files changed

Lines changed: 84 additions & 14 deletions

File tree

readme.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ This test:
5050
```cs
5151
await Verify(connection);
5252
```
53+
<<<<<<< ours
5354
<sup><a href='/src/Tests/Tests.cs#L317-L321' title='Snippet source file'>snippet source</a> | <a href='#snippet-SqlServerSchema' title='Start of snippet'>anchor</a></sup>
55+
=======
56+
<sup><a href='/src/Tests/Tests.cs#L77-L81' title='Snippet source file'>snippet source</a> | <a href='#snippet-SqlServerSchema' title='Start of snippet'>anchor</a></sup>
57+
>>>>>>> theirs
5458
<!-- endSnippet -->
5559
5660
Will result in the following verified file:
@@ -69,7 +73,11 @@ await Verify(connection)
6973
// include only tables and views
7074
.SchemaIncludes(DbObjects.Tables | DbObjects.Views);
7175
```
76+
<<<<<<< ours
7277
<sup><a href='/src/Tests/Tests.cs#L683-L689' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaInclude' title='Start of snippet'>anchor</a></sup>
78+
=======
79+
<sup><a href='/src/Tests/Tests.cs#L443-L449' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaInclude' title='Start of snippet'>anchor</a></sup>
80+
>>>>>>> theirs
7381
<!-- endSnippet -->
7482
7583
Available values:
@@ -107,7 +115,11 @@ await Verify(connection)
107115
_ => _ is TableViewBase ||
108116
_.Name == "MyTrigger");
109117
```
118+
<<<<<<< ours
110119
<sup><a href='/src/Tests/Tests.cs#L708-L716' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaFilter' title='Start of snippet'>anchor</a></sup>
120+
=======
121+
<sup><a href='/src/Tests/Tests.cs#L468-L476' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaFilter' title='Start of snippet'>anchor</a></sup>
122+
>>>>>>> theirs
111123
<!-- endSnippet -->
112124
113125

@@ -129,7 +141,11 @@ command.CommandText = "select Value from MyTable";
129141
var value = await command.ExecuteScalarAsync();
130142
await Verify(value!);
131143
```
144+
<<<<<<< ours
132145
<sup><a href='/src/Tests/Tests.cs#L492-L502' title='Snippet source file'>snippet source</a> | <a href='#snippet-Recording' title='Start of snippet'>anchor</a></sup>
146+
=======
147+
<sup><a href='/src/Tests/Tests.cs#L252-L262' title='Snippet source file'>snippet source</a> | <a href='#snippet-Recording' title='Start of snippet'>anchor</a></sup>
148+
>>>>>>> theirs
133149
<!-- endSnippet -->
134150
135151
Will result in the following verified file:
@@ -184,7 +200,11 @@ await Verify(
184200
sqlEntries = entries
185201
});
186202
```
203+
<<<<<<< ours
187204
<sup><a href='/src/Tests/Tests.cs#L569-L599' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingSpecific' title='Start of snippet'>anchor</a></sup>
205+
=======
206+
<sup><a href='/src/Tests/Tests.cs#L329-L359' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingSpecific' title='Start of snippet'>anchor</a></sup>
207+
>>>>>>> theirs
188208
<!-- endSnippet -->
189209
190210

@@ -212,7 +232,11 @@ var sqlErrorsViaType = entries
212232
.Select(_ => _.Data)
213233
.OfType<ErrorEntry>();
214234
```
235+
<<<<<<< ours
215236
<sup><a href='/src/Tests/Tests.cs#L625-L644' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingReadingResults' title='Start of snippet'>anchor</a></sup>
237+
=======
238+
<sup><a href='/src/Tests/Tests.cs#L385-L404' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingReadingResults' title='Start of snippet'>anchor</a></sup>
239+
>>>>>>> theirs
216240
<!-- endSnippet -->
217241
218242

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
## Tables
2+
3+
### MyTable
4+
5+
```sql
6+
CREATE TABLE [dbo].[MyTable](
7+
[Value] [int] NULL
8+
) ON [PRIMARY]
9+
10+
CREATE NONCLUSTERED INDEX [MyIndex] ON [dbo].[MyTable]
11+
(
12+
[Value] ASC
13+
) ON [PRIMARY]
14+
15+
CREATE TRIGGER MyTrigger
16+
ON MyTable
17+
AFTER UPDATE
18+
AS RAISERROR ('Notify Customer Relations', 16, 10);
19+
20+
ALTER TABLE [dbo].[MyTable] ENABLE TRIGGER [MyTrigger]
21+
```

src/Tests/Tests.cs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
[TestFixture]
22
public class Tests
33
{
4+
static readonly FieldInfo sqlConnectionObjectField =
5+
typeof(ConnectionManager).GetField("m_SqlConnectionObject", BindingFlags.NonPublic | BindingFlags.Instance)!;
6+
47
static SqlInstance sqlInstance;
58

69
static Tests() =>
710
sqlInstance = new(
811
"VerifySqlServer",
912
connection =>
1013
{
11-
var serverConnection = new ServerConnection
12-
{
13-
ConnectionString = connection.ConnectionString,
14-
};
14+
var serverConnection = new ServerConnection();
15+
sqlConnectionObjectField.SetValue(serverConnection, connection);
16+
serverConnection.NonPooledConnection = true;
1517
var server = new Server(serverConnection);
1618
server.ConnectionContext.ExecuteNonQuery(
1719
"""
@@ -854,4 +856,19 @@ await Verify(connection)
854856
.SchemaIncludes(DbObjects.Tables | DbObjects.Views)
855857
.SchemaFilter(_ => _.Name is "MyTable" or "MyView" or "MyProcedure");
856858
}
857-
}
859+
860+
// Verifies the workaround for SMO 181.15.0 + SqlClient 7.0 TypeLoadException.
861+
// SMO's ServerConnection(SqlConnection) constructor references SqlAuthenticationMethod
862+
// which moved from Microsoft.Data.SqlClient to Extensions.Abstractions in SqlClient 7.0.
863+
// The fix avoids that constructor by using reflection to set the SqlConnection directly.
864+
[Test]
865+
public async Task SchemaFromOpenConnection()
866+
{
867+
await using var database = await sqlInstance.Build();
868+
await using var connection = new SqlConnection(database.ConnectionString);
869+
await connection.OpenAsync();
870+
await Verify(connection)
871+
.SchemaFilter(_ => _.Name == "MyTable")
872+
.SchemaIncludes(DbObjects.Tables);
873+
}
874+
}

src/Verify.SqlServer/GlobalUsings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
global using System.Data.Common;
33
global using System.Data.SqlTypes;
44
global using System.Globalization;
5+
global using System.Text.RegularExpressions;
56
global using Microsoft.Data.SqlClient;
67
global using Microsoft.Extensions.DiagnosticAdapter;
78
global using Microsoft.SqlServer.Management.Common;
9+
global using Microsoft.SqlServer.Management.Smo;
810
global using Microsoft.SqlServer.TransactSql.ScriptDom;
911
global using VerifyTests.SqlServer;

src/Verify.SqlServer/SchemaValidation/SchemaSettings.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using Microsoft.SqlServer.Management.Smo;
2-
31
class SchemaSettings
42
{
53
public DbObjects Includes { get; set; } = DbObjects.All;

src/Verify.SqlServer/SchemaValidation/SqlScriptBuilder.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1-
using System.Text.RegularExpressions;
2-
using Microsoft.SqlServer.Management.Smo;
3-
41
class SqlScriptBuilder(SchemaSettings settings)
52
{
3+
// SMO 181.15.0 ServerConnection(SqlConnection) constructor calls InitFromSqlConnection
4+
// which references SqlAuthenticationMethod — a type moved from Microsoft.Data.SqlClient
5+
// to Microsoft.Data.SqlClient.Extensions.Abstractions in SqlClient 7.0. The CLR can't
6+
// resolve the type in the original assembly, causing a TypeLoadException.
7+
//
8+
// Workaround: construct ServerConnection() with default constructor (no InitFromSqlConnection),
9+
// then set the internal m_SqlConnectionObject field via reflection to reuse the open connection.
10+
// SMO detects the connection is already open and uses it directly.
11+
static readonly FieldInfo sqlConnectionObjectField =
12+
typeof(ConnectionManager).GetField("m_SqlConnectionObject", BindingFlags.NonPublic | BindingFlags.Instance)!;
13+
614
static Dictionary<string, string> tableSettingsToScrubLookup;
715

816
static SqlScriptBuilder()
@@ -33,10 +41,12 @@ public string BuildContent(SqlConnection connection)
3341
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
3442
var serverConnection = new ServerConnection
3543
{
44+
NonPooledConnection = true,
3645
ConnectionString = connection.ConnectionString,
3746
};
3847
try
3948
{
49+
sqlConnectionObjectField.SetValue(serverConnection, connection);
4050
var server = new Server(serverConnection);
4151
return BuildContent(server, builder);
4252
}
@@ -240,4 +250,4 @@ script is
240250
"SET QUOTED_IDENTIFIER OFF" or
241251
"SET ANSI_PADDING ON" or
242252
"SET ANSI_PADDING OFF";
243-
}
253+
}

src/Verify.SqlServer/SchemaValidation/VerifySettingsExtensions.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using Microsoft.SqlServer.Management.Smo;
2-
31
namespace VerifyTests;
42

53
public static partial class VerifySettingsSqlExtensions
@@ -81,4 +79,4 @@ internal static SchemaSettings GetSchemaSettings(this IReadOnlyDictionary<string
8179

8280
// Shared instance is safe: callers only read from it, never mutate
8381
static SchemaSettings defaultSettings = new();
84-
}
82+
}

0 commit comments

Comments
 (0)