Skip to content

Implement SqlConnection.GetSchemaAsync #3005

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

edwardneal
Copy link
Contributor

@edwardneal edwardneal commented Nov 14, 2024

Contributes to #646, adding SqlConnection.GetSchemaAsync.

I can't add the IDbColumnSchemaGenerator method because the .NET Framework version of SqlDataReader doesn't yet implement that interface. #2967 tracks this. SqlDataReader.GetSchemaTableAsync requires some extra work with the state machine to guarantee that the column metadata is available, and I'll submit a separate PR for this.

I've added some basic documentation, but this effectively follows the SqlCommand.[Something]Async pattern of "An asynchronous version of [Something], which <etc.>"

I've also moved the netfx GetSchema methods from SqlConnectionHelper.cs to SqlConnection.cs, to align that part of it with netcore. This contributes to the merge slightly.

@@ -107,7 +109,7 @@ protected virtual void Dispose(bool disposing)
}
}

private DataTable ExecuteCommand(DataRow requestedCollectionRow, string[] restrictions, DbConnection connection)
private async ValueTask<DataTable> ExecuteCommandAsync(DataRow requestedCollectionRow, string[] restrictions, DbConnection connection, bool isAsync, CancellationToken cancellationToken)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice to be seeing proper async/await in SqlClient!

Copy link

codecov bot commented Nov 14, 2024

Codecov Report

Attention: Patch coverage is 93.18182% with 3 lines in your changes missing coverage. Please review.

Project coverage is 63.02%. Comparing base (df35633) to head (eb164d6).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ient/src/Microsoft/Data/SqlClient/SqlDataReader.cs 50.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3005      +/-   ##
==========================================
- Coverage   63.30%   63.02%   -0.28%     
==========================================
  Files         280      274       -6     
  Lines       62386    62104     -282     
==========================================
- Hits        39493    39143     -350     
- Misses      22893    22961      +68     
Flag Coverage Δ
addons ?
netcore 67.19% <91.66%> (+0.17%) ⬆️
netfx 62.29% <92.50%> (-3.87%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@edwardneal edwardneal changed the title Implement SqlConnection.GetSchemaAsync Implement SqlConnection.GetSchemaAsync and SqlDataReader.GetSchemaTableAsync Nov 15, 2024
@edwardneal edwardneal marked this pull request as draft November 15, 2024 22:38
This introduces async-over-sync, removing such requires work with the state machine and separate review.
@edwardneal edwardneal marked this pull request as ready for review November 16, 2024 08:56
@edwardneal edwardneal changed the title Implement SqlConnection.GetSchemaAsync and SqlDataReader.GetSchemaTableAsync Implement SqlConnection.GetSchemaAsync Nov 16, 2024
@mdaigle mdaigle added Enhancement 💡 Issues that are feature requests for the drivers we maintain. Public API 🆕 Issues/PRs that introduce new APIs to the driver. labels Nov 25, 2024
@paulmedynski
Copy link
Contributor

@edwardneal - Can you resolve the conflicts, and then I will kick off another CI run?

@edwardneal edwardneal requested a review from a team as a code owner July 2, 2025 21:14
@edwardneal
Copy link
Contributor Author

Thanks @paulmedynski, I've just brought the branch up to date.

@paulmedynski
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 2 pipeline(s).

Copy link
Contributor

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few inconsistencies and questions.

The cancellation token.
</param>
<summary>
An asynchronous version of <see cref="M:Microsoft.Data.SqlClient.SqlConnection.GetSchema()" />, which returns schema information for the data source of this <see cref="T:Microsoft.Data.SqlClient.SqlConnection" />. For more information about scheme, see <see href="https://learn.microsoft.com/sql/connect/ado-net/sql-server-schema-collections">SQL Server Schema Collections</see>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scheme -> schemas ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - corrected in GetSchemaAsync and GetSchema.

@@ -993,6 +993,21 @@ public event Microsoft.Data.SqlClient.SqlInfoMessageEventHandler InfoMessage { a
public override System.Data.DataTable GetSchema(string collectionName) { throw null; }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/GetSchemaCollectionNameRestrictionValues/*'/>
public override System.Data.DataTable GetSchema(string collectionName, string[] restrictionValues) { throw null; }
#if NET
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole file is NET only, so is this #if necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file is also used to build the netstandard2.0 ref assemblies, which doesn't provide this member in the base class.

public override System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaAsync(string collectionName, System.Threading.CancellationToken cancellationToken = default) { throw null; }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/GetSchemaCollectionNameRestrictionValuesAsync/*'/>
public override System.Threading.Tasks.Task<System.Data.DataTable> GetSchemaAsync(string collectionName, string[] restrictionValues, System.Threading.CancellationToken cancellationToken = default) { throw null; }
#else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we missing GetSchemaTableAsync ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed this method from the implementation and the ref assemblies. At the moment, we get the metadata for a result set by getting the SqlDataReader.MetaData property, which synchronously waits on the network. A future PR can perform the work needed to unpick the async-over-sync here and provide a fully async implementation.


Assert.True(dataBases.Rows.Count > 0, "At least one database is expected");

DataTable metaDataCollections = await conn.GetSchemaAsync(DbMetaDataCollectionNames.MetaDataCollections);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we only testing one of the GetSchemaAsync() methods within a transaction, but not the others?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was an artifact of the existing synchronous tests. I've added that coverage to both the async and the sync tests.

@@ -1638,6 +1638,31 @@ public override DataTable GetSchemaTable()
}
}

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml' path='docs/members[@name="SqlDataReader"]/GetSchemaTableAsync/*' />
#if NETFRAMEWORK
internal Task<DataTable> GetSchemaTableAsync(CancellationToken cancellationToken = default)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're missing a test for this new method.

@paulmedynski paulmedynski requested a review from a team July 4, 2025 10:20
Remove SqlDataReader.GetSchemaTableAsync (and references to such.)
Expand test coverage of both GetSchema and GetSchemaAsync.
Correct typo in documentation for GetSchema and GetSchemaAsync.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement 💡 Issues that are feature requests for the drivers we maintain. Public API 🆕 Issues/PRs that introduce new APIs to the driver.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants