Skip to content

Commit 676b9ca

Browse files
authored
Merge pull request #558 from shueybubbles/master
Create SMO samples project
2 parents 0bc9dab + 12b13d4 commit 676b9ca

17 files changed

Lines changed: 772 additions & 1 deletion

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ build/
2121
bld/
2222
[Bb]in/
2323
[Oo]bj/
24+
out/
2425

2526
# Visual Studio 2015 cache/options directory
2627
.vs/
@@ -435,8 +436,8 @@ samples/databases/wide-world-importers/workload-drivers/order-insert/Multithread
435436
/samples/features/epm-framework/5.0/2Reporting/PolicyReports/bin/Debug
436437
/samples/features/epm-framework/5.0/2Reporting/PolicyReports/PolicyDashboard - Backup.rdl
437438
/samples/features/epm-framework/5.0/2Reporting/PolicyReports/PolicyDashboardFiltered.rdl.data
439+
samples/features/sql-management-objects/src/out/CodeCoverage/CodeCoverage.config
438440

439441
# Certificates
440442
*.pem
441443
*.p12
442-

samples/features/readme.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,15 @@ Built-in temporal functions enable you to easily track history of changes in a t
2828

2929
Graph tables enable you to add a non-relational capability to your database.
3030

31+
[SQL Management Objects (SMO)](sql-management-objects)
32+
33+
The SQL Server Management Objects (SMO) Framework is a set of objects designed for programmatic management of Microsoft SQL Server and Microsoft Azure SQL Database. These code snippets demonstrate features of SMO and illustrate how to use SMO properties and collections without sacrificing performance.
34+
3135
## Samples for Business Intelligence features within SQL Server
3236

3337
[Reporting Services (SSRS)](reporting-services)
3438

3539
Reporting Services provides reporting capabilities for your organziation. Reporting Services can be integrated with SharePoint Server or used as a standalone service.
40+
41+
42+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# SmoSamples
2+
3+
This unit test project is meant to demonstrate features of the Sql Management Objects framework and to help developers optimize performance of their SMO-based applications.
4+
5+
6+
### Contents
7+
8+
[About this sample](#about-this-sample)<br/>
9+
[Before you begin](#before-you-begin)<br/>
10+
[Run this sample](#run-this-sample)<br/>
11+
[Sample details](#sample-details)<br/>
12+
[Disclaimers](#disclaimers)<br/>
13+
[Related links](#related-links)<br/>
14+
15+
16+
<a name=about-this-sample></a>
17+
18+
## About this sample
19+
20+
<!-- Delete the ones that don't apply -->
21+
- **Applies to:** SQL Server 2016 (or higher), Azure SQL Database, Azure SQL Data Warehouse
22+
- **Key features:**
23+
- Unit tests and a docker file that demonstrate proper use of SMO features against a working SQL Server instance.
24+
- **Programming Language:**
25+
- C#
26+
27+
<a name=before-you-begin></a>
28+
29+
## Before you begin
30+
31+
To run this sample, you need the following prerequisites.
32+
33+
**Software prerequisites:**
34+
35+
1. SQL Server 2016 (or higher) or an Azure SQL Database with the full WideWorldImporters sample database, or
36+
2. Docker
37+
3. At minimum the dotnet 2.2 SDK, or Visual Studio 2017
38+
39+
<a name=run-this-sample></a>
40+
41+
## Run this sample
42+
If using Docker, use runtests.sh or runtests.cmd as appropriate. If using a separate instance of SQL Server or Azure SQL Database, create a .runsettings file and run the unit tests using Visual Studio or "dotnet vstest".
43+
44+
<a name=sample-details></a>
45+
46+
## Sample details
47+
48+
Each unit test demonstrates a specific aspect of SMO-based application development, either in isolation or in conjunction with other SMO components. <br/>
49+
Feature areas tested include:
50+
1. Efficient use of collections
51+
2. Sql query capture
52+
3. Events
53+
4. URNs
54+
5. Script generation
55+
56+
57+
<a name=related-links></a>
58+
59+
## Related Links
60+
The SMO NuGet package is at https://www.nuget.org/packages/Microsoft.SqlServer.SqlManagementObjects/ <br/>
61+
Documentation for the APIs is at https://docs.microsoft.com/sql/relational-databases/server-management-objects-smo/overview-smo<br/>
62+
The WideWorldImporters sample database can be found at https://github.com/Microsoft/sql-server-samples/releases/download/wide-world-importers-v1.0/WideWorldImporters-Full.bak <br/>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM mcr.microsoft.com/mssql/server:2017-latest
2+
WORKDIR /tmp/backup
3+
RUN wget -q https://github.com/Microsoft/sql-server-samples/releases/download/wide-world-importers-v1.0/WideWorldImporters-Full.bak
4+
COPY restore.sql .
5+
COPY restore.sh .
6+
COPY entrypoint.sh .
7+
CMD ["/bin/bash", "/tmp/backup/entrypoint.sh"]
8+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/opt/mssql/bin/sqlservr & /tmp/backup/restore.sh
2+
tail -f /dev/null
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Wait for SQL Server to start and be ready to accept connections
2+
sleep 35s
3+
echo sa_password is $SA_PASSWORD
4+
/opt/mssql-tools/bin/sqlcmd -S . -U sa -P $SA_PASSWORD -i /tmp/backup/restore.sql
5+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
RESTORE DATABASE WideWorldImporters FROM DISK = "/tmp/backup/WideWorldImporters-Full.bak"
2+
WITH MOVE "WWI_Primary" TO "/var/opt/mssql/data/WideWorldImporters.mdf",
3+
MOVE "WWI_Userdata" TO "/var/opt/mssql/data/WideWorldImporters_UserData.ndf",
4+
MOVE "WWI_Log" TO "/var/opt/mssql/data/WideWorldImporters.ldf", MOVE "WWI_InMemory_Data_1"
5+
TO "/var/opt/mssql/data/WideWorldImporters_InMemory_Data_1"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@echo off
2+
set pwd=Passwd__%random%
3+
echo Building the SQL Linux Docker container
4+
docker pull mcr.microsoft.com/mssql/server:2017-latest
5+
docker build -t sqllinux prep
6+
echo Running the SQL linux docker image
7+
start cmd /k docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=%pwd%" -e "MSSQL_SA_PASSWORD=%pwd%" -h sqlserver --name sqlserver -p:1433:1433 --rm sqllinux
8+
echo Waiting 90 seconds for SQL server to restore WideWorldImporters
9+
timeout /t 90
10+
setlocal
11+
echo running tests against SQL 2017 database WideWorldImporters
12+
set TEST_PASSWORD=%pwd%
13+
dotnet publish src -o out
14+
dotnet vstest src\out\SmoSamples.dll /logger:console /settings:src\localhost.runsettings
15+
endlocal
16+
echo Terminating docker container
17+
docker kill sqlserver
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
pwd=Pwd$RANDOM
2+
echo Building the SQL Linux Docker container
3+
docker pull mcr.microsoft.com/mssql/server:2017-latest
4+
docker build -t sqllinux prep
5+
echo Running the SQL linux docker image
6+
docker run -e ACCEPT_EULA=Y -e SA_PASSWORD=$pwd -e MSSQL_SA_PASSWORD=$pwd -h sqlserver --name sqlserver -p:1433:1433 -d --rm sqllinux
7+
echo Waiting 2 minutes for SQL server to restore WideWorldImporters
8+
sleep 120
9+
echo running tests against SQL 2017 database WideWorldImporters
10+
export TEST_PASSWORD=$pwd
11+
dotnet publish src
12+
dotnet vstest src/bin/Debug/netcoreapp2.1/SmoSamples.dll --logger:console --Settings:src/localhost.runsettings
13+
echo Terminating docker container
14+
docker kill sqlserver
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
namespace Microsoft.SqlServer.SmoSamples
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Diagnostics;
6+
using System.Text;
7+
using Microsoft.SqlServer.Management.Smo;
8+
using Microsoft.VisualStudio.TestTools.UnitTesting;
9+
using NUnit.Framework;
10+
using Assert = NUnit.Framework.Assert;
11+
12+
[TestClass]
13+
public class CollectionSamples
14+
{
15+
public VisualStudio.TestTools.UnitTesting.TestContext TestContext { get; set; }
16+
17+
/// <summary>
18+
/// SetDefaultInitFields tells the Server object which properties to include in the initial query
19+
/// to populate of a given object type when initialized a collection of that type.
20+
/// The test demonstrates the effect of using this call to enumerate Tables when accessing the FileGroup
21+
/// property of each Table object
22+
/// </summary>
23+
[TestMethod]
24+
public void Collection_iteration_is_faster_with_SetDefaultInitFields()
25+
{
26+
using (var connectionMetrics = ConnectionMetrics.SetupMeasuredConnection(TestContext, 50))
27+
{
28+
var server = new Management.Smo.Server(connectionMetrics.ServerConnection);
29+
var database = server.Databases[TestContext.GetTestDatabaseName()];
30+
connectionMetrics.Reset();
31+
foreach (Table table in database.Tables)
32+
{
33+
// Accessing FileGroup triggers a query to fetch it
34+
Trace.TraceInformation(
35+
$"Unoptimized table Name: {table.Name}\tSchema:{table.Schema}\tFileGroup:{table.FileGroup}");
36+
}
37+
38+
var unoptimizedMetrics = (QueryCount: connectionMetrics.QueryCount,
39+
BytesSent: connectionMetrics.BytesSent, BytesRead: connectionMetrics.BytesRead,
40+
ConnectionCount: connectionMetrics.ConnectionCount);
41+
Trace.TraceInformation(string.Join($"{Environment.NewLine}\t", new[]
42+
{
43+
"Unoptimized metrics:",
44+
$"QueryCount:{unoptimizedMetrics.QueryCount}", $"ConnectionCount:{unoptimizedMetrics.ConnectionCount}",
45+
$"BytesSent:{unoptimizedMetrics.BytesSent}", $"BytesRead:{unoptimizedMetrics.BytesRead}"
46+
}));
47+
48+
connectionMetrics.Reset();
49+
server.SetDefaultInitFields(typeof(Table), "Name", "Schema", "FileGroup");
50+
database.Tables.Refresh();
51+
foreach (Table table in database.Tables)
52+
{
53+
// The FileGroup property is already populated, so no extra query is needed
54+
Trace.TraceInformation(
55+
$"Optimized table Name: {table.Name}\tSchema:{table.Schema}\tFileGroup:{table.FileGroup}");
56+
}
57+
58+
var optimizedMetrics = (QueryCount: connectionMetrics.QueryCount,
59+
BytesSent: connectionMetrics.BytesSent, BytesRead: connectionMetrics.BytesRead,
60+
ConnectionCount: connectionMetrics.ConnectionCount);
61+
Trace.TraceInformation(string.Join($"{Environment.NewLine}\t", new[]
62+
{
63+
"Optimized Metrics:",
64+
$"QueryCount:{optimizedMetrics.QueryCount}", $"ConnectionCount:{optimizedMetrics.ConnectionCount}",
65+
$"BytesSent:{optimizedMetrics.BytesSent}", $"BytesRead:{optimizedMetrics.BytesRead}"
66+
}));
67+
Assert.That(optimizedMetrics.BytesRead, Is.LessThan(unoptimizedMetrics.BytesRead), "BytesRead");
68+
Assert.That(optimizedMetrics.BytesSent, Is.LessThan(unoptimizedMetrics.BytesSent), "BytesSent");
69+
Assert.That(optimizedMetrics.ConnectionCount, Is.AtMost(unoptimizedMetrics.ConnectionCount), "ConnectionCount");
70+
Assert.That(optimizedMetrics.QueryCount, Is.LessThan(unoptimizedMetrics.QueryCount), "QueryCount");
71+
}
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)