Skip to content

Commit 42b9747

Browse files
committed
2 parents 65c46ce + cf864b0 commit 42b9747

8 files changed

Lines changed: 68 additions & 20 deletions

File tree

readme.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ This test:
5050
```cs
5151
await Verify(connection);
5252
```
53-
<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>
53+
<sup><a href='/src/Tests/Tests.cs#L316-L320' title='Snippet source file'>snippet source</a> | <a href='#snippet-SqlServerSchema' title='Start of snippet'>anchor</a></sup>
5454
<!-- endSnippet -->
5555

5656
Will result in the following verified file:
@@ -69,7 +69,7 @@ await Verify(connection)
6969
// include only tables and views
7070
.SchemaIncludes(DbObjects.Tables | DbObjects.Views);
7171
```
72-
<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>
72+
<sup><a href='/src/Tests/Tests.cs#L682-L688' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaInclude' title='Start of snippet'>anchor</a></sup>
7373
<!-- endSnippet -->
7474

7575
Available values:
@@ -107,7 +107,7 @@ await Verify(connection)
107107
_ => _ is TableViewBase ||
108108
_.Name == "MyTrigger");
109109
```
110-
<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>
110+
<sup><a href='/src/Tests/Tests.cs#L707-L715' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaFilter' title='Start of snippet'>anchor</a></sup>
111111
<!-- endSnippet -->
112112

113113

@@ -129,7 +129,7 @@ command.CommandText = "select Value from MyTable";
129129
var value = await command.ExecuteScalarAsync();
130130
await Verify(value!);
131131
```
132-
<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>
132+
<sup><a href='/src/Tests/Tests.cs#L491-L501' title='Snippet source file'>snippet source</a> | <a href='#snippet-Recording' title='Start of snippet'>anchor</a></sup>
133133
<!-- endSnippet -->
134134

135135
Will result in the following verified file:
@@ -184,7 +184,7 @@ await Verify(
184184
sqlEntries = entries
185185
});
186186
```
187-
<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>
187+
<sup><a href='/src/Tests/Tests.cs#L568-L598' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingSpecific' title='Start of snippet'>anchor</a></sup>
188188
<!-- endSnippet -->
189189

190190

@@ -212,7 +212,7 @@ var sqlErrorsViaType = entries
212212
.Select(_ => _.Data)
213213
.OfType<ErrorEntry>();
214214
```
215-
<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>
215+
<sup><a href='/src/Tests/Tests.cs#L624-L643' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingReadingResults' title='Start of snippet'>anchor</a></sup>
216216
<!-- endSnippet -->
217217

218218

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: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ static Tests() =>
88
"VerifySqlServer",
99
connection =>
1010
{
11-
var serverConnection = new ServerConnection
12-
{
13-
ConnectionString = connection.ConnectionString,
14-
};
11+
var serverConnection = new ServerConnection();
12+
SqlScriptBuilder.SqlConnectionObjectField.SetValue(serverConnection, connection);
13+
serverConnection.NonPooledConnection = true;
1514
var server = new Server(serverConnection);
1615
server.ConnectionContext.ExecuteNonQuery(
1716
"""
@@ -854,4 +853,19 @@ await Verify(connection)
854853
.SchemaIncludes(DbObjects.Tables | DbObjects.Views)
855854
.SchemaFilter(_ => _.Name is "MyTable" or "MyView" or "MyProcedure");
856855
}
857-
}
856+
857+
// Verifies the workaround for SMO 181.15.0 + SqlClient 7.0 TypeLoadException.
858+
// SMO's ServerConnection(SqlConnection) constructor references SqlAuthenticationMethod
859+
// which moved from Microsoft.Data.SqlClient to Extensions.Abstractions in SqlClient 7.0.
860+
// The fix avoids that constructor by using reflection to set the SqlConnection directly.
861+
[Test]
862+
public async Task SchemaFromOpenConnection()
863+
{
864+
await using var database = await sqlInstance.Build();
865+
await using var connection = new SqlConnection(database.ConnectionString);
866+
await connection.OpenAsync();
867+
await Verify(connection)
868+
.SchemaFilter(_ => _.Name == "MyTable")
869+
.SchemaIncludes(DbObjects.Tables);
870+
}
871+
}

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: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1-
using System.Text.RegularExpressions;
2-
using Microsoft.SqlServer.Management.Smo;
3-
41
class SqlScriptBuilder(SchemaSettings settings)
52
{
3+
// TODO: when Microsoft.Data.SqlClient 7.0.1 adds TypeForwardedTo for SqlAuthenticationMethod,
4+
// revert to using new ServerConnection(SqlConnection) and remove this reflection workaround.
5+
//
6+
// SMO 181.15.0 ServerConnection(SqlConnection) constructor calls InitFromSqlConnection
7+
// which references SqlAuthenticationMethod — a type moved from Microsoft.Data.SqlClient
8+
// to Microsoft.Data.SqlClient.Extensions.Abstractions in SqlClient 7.0. The CLR can't
9+
// resolve the type in the original assembly, causing a TypeLoadException.
10+
//
11+
// Workaround: construct ServerConnection() with default constructor (no InitFromSqlConnection),
12+
// then set the internal m_SqlConnectionObject field via reflection to reuse the open connection.
13+
// SMO detects the connection is already open and uses it directly.
14+
internal static readonly FieldInfo SqlConnectionObjectField =
15+
typeof(ConnectionManager).GetField("m_SqlConnectionObject", BindingFlags.NonPublic | BindingFlags.Instance) ??
16+
throw new("Could not find field m_SqlConnectionObject on ConnectionManager. The SMO internals may have changed.");
17+
618
static Dictionary<string, string> tableSettingsToScrubLookup;
719

820
static SqlScriptBuilder()
@@ -33,10 +45,12 @@ public string BuildContent(SqlConnection connection)
3345
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
3446
var serverConnection = new ServerConnection
3547
{
48+
NonPooledConnection = true,
3649
ConnectionString = connection.ConnectionString,
3750
};
3851
try
3952
{
53+
SqlConnectionObjectField.SetValue(serverConnection, connection);
4054
var server = new Server(serverConnection);
4155
return BuildContent(server, builder);
4256
}
@@ -240,4 +254,4 @@ script is
240254
"SET QUOTED_IDENTIFIER OFF" or
241255
"SET ANSI_PADDING ON" or
242256
"SET ANSI_PADDING OFF";
243-
}
257+
}

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+
}

src/Verify.SqlServer/Verify.SqlServer.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<TargetFrameworks>net48;net8.0;net9.0;net10.0</TargetFrameworks>
44
</PropertyGroup>
55
<ItemGroup>
6+
<InternalsVisibleTo Include="Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000f0a8e4bf1639dce01be6592384e7dfc621915b7759fb5cee42ec5d351bcc43460432da1659ee618ca6cab6b8b8e56a5deb5d4ee1a49783d5c2690752502d31ccbfee9b2c697e20359b55ad100cc9370c8e983fd9496f01d761a060d0435bac7243b1832ba95757aa5adbb67df38c213d717b6751e1217cea9fa5c61e9b799dd" />
67
<PackageReference Include="Microsoft.Data.SqlClient" />
78
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" />
89
<PackageReference Include="Microsoft.SqlServer.TransactSql.ScriptDom" />

0 commit comments

Comments
 (0)