├── dotnet-dbinfo ├── Properties │ └── launchSettings.json ├── SupportedDatabaseType.cs ├── dotnet-dbinfo.csproj ├── InfoCollectors │ ├── MongoDbInfoCollector.cs │ ├── CosmosDbInfoCollector.cs │ ├── DynamoDbInfoCollector.cs │ └── SqlServerInfoCollector.cs ├── Helpers.cs └── Program.cs ├── .gitignore ├── LICENSE ├── dotnet-dbinfo.sln └── README.md /dotnet-dbinfo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "dotnet-dbinfo": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /dotnet-dbinfo/SupportedDatabaseType.cs: -------------------------------------------------------------------------------- 1 | namespace dotnet_dbinfo 2 | { 3 | public enum SupportedDatabaseType 4 | { 5 | SQLSERVER, 6 | DYNAMODB, 7 | COSMOSDB, 8 | MONGODB, 9 | SQLAZURE 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | /.vs 6 | /.vscode 7 | /*/obj 8 | /*/bin 9 | /*/.vscode 10 | *.dbmdl 11 | *.jfm 12 | /packages 13 | *.user 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dotnet-dbinfo.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2018 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-dbinfo", "dotnet-dbinfo\dotnet-dbinfo.csproj", "{772F133A-EF5E-48BD-AAAF-3F7B1E4B5D0A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {772F133A-EF5E-48BD-AAAF-3F7B1E4B5D0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {772F133A-EF5E-48BD-AAAF-3F7B1E4B5D0A}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {772F133A-EF5E-48BD-AAAF-3F7B1E4B5D0A}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {772F133A-EF5E-48BD-AAAF-3F7B1E4B5D0A}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {56F67413-77E7-42FC-AEDE-C271BA633A4E} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /dotnet-dbinfo/dotnet-dbinfo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | dotnet_dbinfo 7 | true 8 | berkid89 9 | 10 | 11 | 1.4.0 12 | A simple command-line tool for get useful database information (in json format). Supported ones: Microsoft SQL Server, AWS DynamoDb, Azure CosmosDb, MongoDb 13 | https://github.com/berkid89/dotnet-dbinfo 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /dotnet-dbinfo/InfoCollectors/MongoDbInfoCollector.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Driver; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using static dotnet_dbinfo.Helpers; 5 | 6 | namespace dotnet_dbinfo.InfoCollectors 7 | { 8 | public static class MongoDbInfoCollector 9 | { 10 | public static object CollectMongoDbInfo(MongoClient conn, string database) 11 | { 12 | var db = conn.GetDatabase(database); 13 | 14 | return new 15 | { 16 | general = GetGeneralInfo(db), 17 | collections = GetCollectionInfo(db), 18 | }; 19 | } 20 | 21 | private static object GetGeneralInfo(IMongoDatabase db) => 22 | new 23 | { 24 | DatabaseId = db.DatabaseNamespace.DatabaseName, 25 | }; 26 | 27 | private static IEnumerable GetCollectionInfo(IMongoDatabase db) => 28 | db.ListCollectionNames().ToList().Select(p => MapStats(db.RunCommand($"{{collstats: '{p}'}}"))); 29 | 30 | private static object MapStats(dynamic stats) => 31 | new 32 | { 33 | stats.ns, 34 | SizeInMb = ConvertBytesToMegabytes(stats.size), 35 | stats.count, 36 | StorageSizeInMb = ConvertBytesToMegabytes(stats.storageSize), 37 | stats.capped, 38 | stats.nindexes, 39 | TotalIndexSizeInMb = ConvertBytesToMegabytes(stats.totalIndexSize), 40 | stats.ok 41 | }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dotnet-dbinfo/InfoCollectors/CosmosDbInfoCollector.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Azure.Documents; 2 | using Microsoft.Azure.Documents.Client; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace dotnet_dbinfo.InfoCollectors 8 | { 9 | public static class CosmosDbInfoCollector 10 | { 11 | public static object CollectCosmosDbInfo(DocumentClient conn, string database) => 12 | new 13 | { 14 | general = GetGeneralInfo(conn, database), 15 | collections = GetCollectionInfo(conn, UriFactory.CreateDatabaseUri(database)), 16 | }; 17 | 18 | private static object GetGeneralInfo(DocumentClient conn, string database) 19 | { 20 | Database result = conn.CreateDatabaseQuery($"SELECT * FROM dbs d WHERE d.id = '{database}'").ToList().First(); 21 | 22 | return new 23 | { 24 | result.Id, 25 | result.AltLink, 26 | }; 27 | } 28 | 29 | private static IEnumerable GetCollectionInfo(DocumentClient conn, Uri databaseUri) => 30 | conn.CreateDocumentCollectionQuery(databaseUri).ToList().Select(p => new 31 | { 32 | p.Id, 33 | p.AltLink, 34 | DocumentCount = conn.CreateDocumentQuery(p.SelfLink, "SELECT VALUE COUNT(1) FROM c").ToList().First(), 35 | StoredProcedures = conn.CreateStoredProcedureQuery(p.SelfLink).ToList().Select(sp => sp.Id), 36 | UserDefinedFunctions = conn.CreateUserDefinedFunctionQuery(p.SelfLink).ToList().Select(uf => uf.Id), 37 | Triggers = conn.CreateTriggerQuery(p.SelfLink).ToList().Select(t => t.Id) 38 | }).ToList(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dotnet-dbinfo/InfoCollectors/DynamoDbInfoCollector.cs: -------------------------------------------------------------------------------- 1 | using Amazon.DynamoDBv2; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using static dotnet_dbinfo.Helpers; 5 | 6 | namespace dotnet_dbinfo.InfoCollectors 7 | { 8 | public static class DynamoDbInfoCollector 9 | { 10 | public static object CollectDynamoDbInfo(AmazonDynamoDBClient conn) => 11 | new 12 | { 13 | general = GetGeneralInfo(conn), 14 | tables = GetTableInfo(conn), 15 | }; 16 | 17 | private static object GetGeneralInfo(AmazonDynamoDBClient conn) => 18 | new 19 | { 20 | ServiceName = conn.Config.RegionEndpointServiceName, 21 | Region = $"{conn.Config.RegionEndpoint.DisplayName} ({conn.Config.RegionEndpoint.SystemName})", 22 | conn.Config.ServiceVersion 23 | }; 24 | 25 | private static IEnumerable GetTableInfo(AmazonDynamoDBClient conn) => 26 | conn.ListTablesAsync().Result.TableNames.Select(p => conn.DescribeTableAsync(p).Result.Table).ToList().Select(table => 27 | { 28 | return new 29 | { 30 | table.TableName, 31 | table.ItemCount, 32 | TableSizeInMb = ConvertBytesToMegabytes(table.TableSizeBytes), 33 | CreateDate = table.CreationDateTime, 34 | Status = table.TableStatus.Value, 35 | GlobalSecondaryIndexes = table.GlobalSecondaryIndexes.Select(p => new 36 | { 37 | p.IndexName, 38 | IndexItemCount = p.ItemCount, 39 | IndexSizeInMb = ConvertBytesToMegabytes(p.IndexSizeBytes), 40 | IndexStatus = p.IndexStatus.Value 41 | }) 42 | }; 43 | }).ToList(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dotnet-dbinfo/Helpers.cs: -------------------------------------------------------------------------------- 1 | using Amazon; 2 | using Amazon.DynamoDBv2; 3 | using Microsoft.Azure.Documents.Client; 4 | using MongoDB.Driver; 5 | using System; 6 | using System.Data.SqlClient; 7 | using System.Linq; 8 | 9 | namespace dotnet_dbinfo 10 | { 11 | public static class Helpers 12 | { 13 | public static R ConnectToSqlServer(string connStr, bool isSQLAzure, Func f) => Using(new SqlConnection(connStr), conn => { conn.Open(); return f(conn, isSQLAzure); }); 14 | 15 | public static R ConnectToDynamoDb(string awsAccessKeyId, string awsSecretAccessKey, string regionEndpoint, Func f) => Using( 16 | GetDynamoDbClient(awsAccessKeyId, awsSecretAccessKey, regionEndpoint) 17 | , conn => { return f(conn); }); 18 | 19 | public static R ConnectToCosmosDb(string endpointUri, string primaryKey, string database, Func f) => Using(new DocumentClient(new Uri(endpointUri), primaryKey), conn => { return f(conn, database); }); 20 | 21 | public static R ConnectToMongoDb(string connStr, string database, Func f) => f(new MongoClient(connStr), database); 22 | 23 | static AmazonDynamoDBClient GetDynamoDbClient(string awsAccessKeyId, string awsSecretAccessKey, string regionEndpoint) 24 | { 25 | var region = RegionEndpoint.EnumerableAllRegions.First(p => p.SystemName == regionEndpoint); 26 | 27 | if (string.IsNullOrEmpty(awsAccessKeyId) || string.IsNullOrEmpty(awsSecretAccessKey)) 28 | return new AmazonDynamoDBClient(region); 29 | else 30 | return new AmazonDynamoDBClient(awsAccessKeyId, awsSecretAccessKey, region); 31 | } 32 | 33 | static R Using(TDisp client, Func func) where TDisp : IDisposable 34 | { 35 | using (var disp = client) return func(disp); 36 | } 37 | 38 | public static double ConvertBytesToMegabytes(long bytes) => (bytes / 1024f) / 1024f; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dotnet-dbinfo 2 | 3 | [![NuGet][main-nuget-badge]][main-nuget] 4 | 5 | [main-nuget]: https://www.nuget.org/packages/dotnet-dbinfo/ 6 | [main-nuget-badge]: https://img.shields.io/nuget/v/dotnet-dbinfo.svg?style=flat-square&label=nuget 7 | 8 | A simple cross-platform command-line tool for get useful database information (in json format). 9 | 10 | ## Get started 11 | 12 | Download the .NET Core SDK [2.1.300](https://aka.ms/DotNetCore21) or newer. 13 | Once installed, run this command: 14 | 15 | ``` 16 | dotnet tool install -g dotnet-dbinfo 17 | ``` 18 | 19 | Or update to the latest version: 20 | ``` 21 | dotnet tool update -g dotnet-dbinfo 22 | ``` 23 | 24 | ## Usage 25 | 26 | ### Microsoft SQL Server 27 | 28 | ``` 29 | Usage: dotnet dbinfo sqlserver server database user password 30 | 31 | Arguments: 32 | 33 | server Name of the database server 34 | 35 | database Name of the database instance 36 | 37 | user Login name of the user 38 | 39 | password Password of the user 40 | ``` 41 | 42 | Example: 43 | ``` 44 | dotnet dbinfo sqlserver .\SQLEXPRESS master sa Pass1234 45 | ``` 46 | 47 | ### Azure SQL 48 | 49 | ``` 50 | Usage: dotnet dbinfo sqlazure server database user password 51 | 52 | Arguments: 53 | 54 | server Name of the database server 55 | 56 | database Name of the database instance 57 | 58 | user Login name of the user 59 | 60 | password Password of the user 61 | ``` 62 | 63 | Example: 64 | ``` 65 | dotnet dbinfo sqlazure .\SQLEXPRESS master sa Pass1234 66 | ``` 67 | 68 | 69 | ### AWS DynamoDb 70 | 71 | ``` 72 | Usage: dotnet dbinfo dynamodb regionendpoint [accesskey] [secretkey] 73 | 74 | Arguments: 75 | 76 | regionendpoint Region (for example: us-east-1) 77 | 78 | accesskey/secretkey (OPTIONAL) If not set, tool uses AWS credentials profile file on your local system 79 | 80 | ``` 81 | 82 | Example: 83 | ``` 84 | dotnet dbinfo dynamodb us-east-1 85 | ``` 86 | 87 | ### Azure CosmosDb 88 | 89 | ``` 90 | Usage: dotnet dbinfo cosmosdb endpointUri primaryKey database 91 | 92 | Arguments: 93 | 94 | endpointUri Your endpoint URL from the Portal 95 | 96 | primaryKey Your primary key 97 | 98 | database Name of the database 99 | 100 | ``` 101 | 102 | Example: 103 | ``` 104 | dotnet dbinfo cosmosdb https://test.documents.azure.com:443/ Y7Tr6jZy10Jh6FOo4hCP4LR128ekLOczs4a5fQlEjH0TehgWfOdilWp2GvyQ1pmDxP3zQFXF11CclKgsg9vMz4Q== ToDoList 105 | ``` 106 | 107 | ### MongoDb 108 | 109 | ``` 110 | Usage: dotnet dbinfo mongodb host:port database user password 111 | 112 | Arguments: 113 | 114 | host:port Host and port of the MongoDb server 115 | 116 | database Name of the database 117 | 118 | user Login name of the user 119 | 120 | password Password of the user 121 | 122 | ``` 123 | 124 | Example: 125 | ``` 126 | dotnet dbinfo mongodb localhost:27017 my_database my_user password123 127 | ``` 128 | 129 | > **Hint:** The **user** must have the necessary **permissions** for the database! 130 | -------------------------------------------------------------------------------- /dotnet-dbinfo/Program.cs: -------------------------------------------------------------------------------- 1 | using dotnet_dbinfo.InfoCollectors; 2 | using dotnet_dbinfo.InfoCollectors.SqlServer; 3 | using MongoDB.Driver; 4 | using Newtonsoft.Json; 5 | using Newtonsoft.Json.Serialization; 6 | using System; 7 | using System.Linq; 8 | using static dotnet_dbinfo.Helpers; 9 | 10 | namespace dotnet_dbinfo 11 | { 12 | static class Program 13 | { 14 | private const int ERROR = 2; 15 | private const int OK = 0; 16 | 17 | static int Main(string[] args) 18 | { 19 | try 20 | { 21 | switch (GetDbType(GetArg(args, 0))) 22 | { 23 | case SupportedDatabaseType.SQLSERVER: 24 | Console.Write( 25 | Serialize( 26 | ConnectToSqlServer($"data source={GetArg(args, 1)};initial catalog={GetArg(args, 2)};User Id={GetArg(args, 3)};Password ={GetArg(args, 4)};", false, SqlServerInfoCollector.CollectSqlServerDbInfo) 27 | )); 28 | break; 29 | case SupportedDatabaseType.DYNAMODB: 30 | Console.Write( 31 | Serialize( 32 | ConnectToDynamoDb(GetArg(args, 2), GetArg(args, 3), GetArg(args, 1), DynamoDbInfoCollector.CollectDynamoDbInfo) 33 | )); 34 | break; 35 | case SupportedDatabaseType.COSMOSDB: 36 | Console.Write( 37 | Serialize( 38 | ConnectToCosmosDb(GetArg(args, 1), GetArg(args, 2), GetArg(args, 3), CosmosDbInfoCollector.CollectCosmosDbInfo) 39 | )); 40 | break; 41 | case SupportedDatabaseType.MONGODB: 42 | Console.WriteLine( 43 | Serialize( 44 | ConnectToMongoDb($"mongodb://{GetArg(args, 3)}:{GetArg(args, 4)}@{GetArg(args, 1)}/{GetArg(args, 2)}", GetArg(args, 2), MongoDbInfoCollector.CollectMongoDbInfo) 45 | )); 46 | break; 47 | case SupportedDatabaseType.SQLAZURE: 48 | Console.Write( 49 | Serialize( 50 | ConnectToSqlServer($"data source={GetArg(args, 1)};initial catalog={GetArg(args, 2)};User Id={GetArg(args, 3)};Password ={GetArg(args, 4)};", true, SqlServerInfoCollector.CollectSqlServerDbInfo) 51 | )); 52 | break; 53 | } 54 | #if DEBUG 55 | Console.ReadKey(); 56 | #endif 57 | 58 | return OK; 59 | } 60 | catch (Exception ex) 61 | { 62 | Console.ForegroundColor = ConsoleColor.Red; 63 | Console.Error.WriteLine("Unexpected error: " + ex.ToString()); 64 | Console.ResetColor(); 65 | 66 | #if DEBUG 67 | Console.ReadKey(); 68 | #endif 69 | 70 | return ERROR; 71 | } 72 | } 73 | 74 | static SupportedDatabaseType GetDbType(string type) => 75 | Enum.Parse(type, true); 76 | 77 | static string Serialize(object obj) => 78 | JsonConvert.SerializeObject(obj, new JsonSerializerSettings 79 | { 80 | ContractResolver = new CamelCasePropertyNamesContractResolver(), 81 | Formatting = Formatting.Indented 82 | }); 83 | 84 | static string GetArg(string[] args, int index) 85 | { 86 | if (args.Count() > index) 87 | return args[index]; 88 | else 89 | return null; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /dotnet-dbinfo/InfoCollectors/SqlServerInfoCollector.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data.SqlClient; 3 | 4 | namespace dotnet_dbinfo.InfoCollectors.SqlServer 5 | { 6 | public static class SqlServerInfoCollector 7 | { 8 | public static object CollectSqlServerDbInfo(SqlConnection conn, bool isAzureSQL) => 9 | new 10 | { 11 | general = GetGeneralInfo(conn), 12 | tables = GetTableInfo(conn, isAzureSQL), 13 | fragmentedIndexes = GetFragmentedIndexes(conn) 14 | }; 15 | 16 | 17 | private static object GetGeneralInfo(SqlConnection conn) 18 | { 19 | var command = new SqlCommand($@" 20 | SELECT [database_id] [DatabaseId], [name] [Name], [create_date] [CreateDate], [collation_name] [Collation], [state_desc] [State] 21 | FROM sys.databases 22 | WHERE [name] = '{conn.Database}'", conn); 23 | 24 | using (var reader = command.ExecuteReader()) 25 | { 26 | while (reader.Read()) 27 | { 28 | return new 29 | { 30 | DatabaseId = reader[0], 31 | Name = reader[1], 32 | CreateDate = reader[2], 33 | Collation = reader[3], 34 | State = reader[4] 35 | }; 36 | } 37 | } 38 | 39 | return new { }; 40 | } 41 | 42 | private static IEnumerable GetFragmentedIndexes(SqlConnection conn) 43 | { 44 | var result = new List(); 45 | 46 | var command = new SqlCommand(@" 47 | SELECT 48 | dbindexes.[object_id] [ObjectId], 49 | dbindexes.[name] [Index], 50 | dbindexes.[type_desc] [Type], 51 | '[' + dbschemas.[name] + '].[' + dbtables.[name] + ']' [TableName], 52 | indexstats.[avg_fragmentation_in_percent] as [AvgFragmentationInPercent] 53 | FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats 54 | INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id] 55 | INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id] 56 | INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id] AND indexstats.index_id = dbindexes.index_id 57 | WHERE indexstats.database_id = DB_ID() and indexstats.avg_fragmentation_in_percent > 5 58 | ORDER BY indexstats.avg_fragmentation_in_percent desc", conn); 59 | 60 | using (var reader = command.ExecuteReader()) 61 | { 62 | while (reader.Read()) 63 | { 64 | result.Add(new 65 | { 66 | ObjectId = reader[0], 67 | Index = reader[1], 68 | Type = reader[2], 69 | TableName = reader[3], 70 | AvgFragmentationInPercent = reader[4] 71 | }); 72 | } 73 | } 74 | 75 | return result; 76 | } 77 | 78 | private static IEnumerable GetTableInfo(SqlConnection conn, bool isAzureSQL) 79 | { 80 | var result = new List(); 81 | var sql = ""; 82 | if (isAzureSQL) 83 | { 84 | sql = @"DECLARE @TableRowCounts TABLE ([TableName] VARCHAR(128), [ItemCount] BIGINT) ; 85 | INSERT INTO @TableRowCounts([TableName], [ItemCount]) 86 | SELECT t.name ,s.row_count 87 | FROM sys.tables t 88 | JOIN sys.dm_db_partition_stats s ON t.object_id = s.object_id 89 | SELECT [TableName], [ItemCount] 90 | FROM @TableRowCounts 91 | ORDER BY[TableName]"; 92 | } 93 | else 94 | { 95 | sql = @"DECLARE @TableRowCounts TABLE ([TableName] VARCHAR(128), [ItemCount] BIGINT) ; 96 | INSERT INTO @TableRowCounts([TableName], [ItemCount]) 97 | EXEC sp_MSforeachtable 'SELECT ''?'' [TableName], COUNT(*) [ItemCount] FROM ?'; 98 | SELECT [TableName], [ItemCount] 99 | FROM @TableRowCounts 100 | ORDER BY[TableName]"; 101 | } 102 | 103 | var command = new SqlCommand(sql, conn); 104 | using (var reader = command.ExecuteReader()) 105 | { 106 | while (reader.Read()) 107 | { 108 | result.Add(new 109 | { 110 | TableName = reader[0], 111 | ItemCount = reader[1], 112 | }); 113 | } 114 | } 115 | 116 | return result; 117 | } 118 | } 119 | } 120 | --------------------------------------------------------------------------------