33
44using System ;
55using System . Collections . Generic ;
6+ using System . Linq ;
67using System . Reflection ;
78using System . Runtime . CompilerServices ;
89using System . Threading . Tasks ;
910using Microsoft . EntityFrameworkCore ;
11+ using Microsoft . EntityFrameworkCore . Metadata ;
1012using Microsoft . Extensions . Configuration ;
1113using Npgsql ;
1214using Respawn ;
@@ -21,6 +23,8 @@ namespace Test.Helpers
2123 /// </summary>
2224 public static class PostgreSqlHelpers
2325 {
26+ private const string DefaultPostgreSqlSchemaName = "public" ;
27+
2428 /// <summary>
2529 /// This creates the DbContextOptions options for a PostgreSql database,
2630 /// where the database name is formed using the appsetting's PostgreSqlConnection with the class name as a prefix.
@@ -99,13 +103,41 @@ public async static Task EnsureCreatedAndEmptyPostgreSqlAsync<T>(this T context)
99103 {
100104 if ( ! context . Database . EnsureCreated ( ) )
101105 {
102- //Already created, so wipe it using respwan
106+ //the database arealy exists, so we just need to empty the tables
107+
103108 var connectionString = context . Database . GetConnectionString ( ) ;
104- using ( var conn = new NpgsqlConnection ( connectionString ) )
109+ //THIS WAS SLOWER THAN USING RESPAWN
110+ //var schemaNames = context.Model.GetEntityTypes().Select(entity =>
111+ // (string?)entity.GetAnnotation(RelationalAnnotationNames.Schema).Value)
112+ // .Distinct().ToList();
113+ //if (schemaNames.Count() == 1)
114+ //{
115+ // //There is only one schema name so we can use the quick way
116+ // //see https://stackoverflow.com/questions/3327312/how-can-i-drop-all-the-tables-in-a-postgresql-database
117+
118+ // var schemaName = schemaNames[0] ?? DefaultPostgreSqlSchemaName;
119+
120+ // //This removes all the tables
121+ // connectionString.ExecuteScalars(
122+ // $"DROP SCHEMA {schemaName} CASCADE",
123+ // $"CREATE SCHEMA {schemaName}",
124+ // $"GRANT ALL ON SCHEMA {schemaName} TO postgres",
125+ // $"GRANT ALL ON SCHEMA {schemaName} TO public"
126+ // );
127+ // //Now add the tables to the database
128+ // context.Database.EnsureCreated();
129+ //}
130+ //else
105131 {
106- await conn . OpenAsync ( ) ;
107- await EmptyCheckpoint . Reset ( conn ) ;
132+ //mutiple schema names, so use respawn approach
133+ using ( var conn = new NpgsqlConnection ( connectionString ) )
134+ {
135+ await conn . OpenAsync ( ) ;
136+ await EmptyCheckpoint . Reset ( conn ) ;
137+ }
108138 }
139+
140+
109141 } ;
110142 }
111143
@@ -128,31 +160,34 @@ public static int DeleteAllPostgreSqlUnitTestDatabases()
128160 builder . Database = "postgres" ;
129161 foreach ( var databaseName in databaseNamesToDelete )
130162 {
131- using ( NpgsqlConnection conn = new NpgsqlConnection ( builder . ToString ( ) ) )
132- {
133- void ExecuteScalar ( string cmdText )
134- {
135- using ( NpgsqlCommand cmd = new NpgsqlCommand ( cmdText , conn ) )
136- {
137- var result = cmd . ExecuteScalar ( ) ;
138- }
139- }
140-
141- conn . Open ( ) ;
142- //The following commands were taken from EF Core
143- //also see https://www.postgresqltutorial.com/postgresql-drop-database/ for another form
144- ExecuteScalar ( $ "REVOKE CONNECT ON DATABASE \" { databaseName } \" FROM PUBLIC") ;
145- ExecuteScalar ( "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity " +
146- $ "WHERE datname = '{ databaseName } '") ;
147- ExecuteScalar ( $ "DROP DATABASE \" { databaseName } \" ") ;
148- }
163+ builder . ToString ( ) . ExecuteScalars (
164+ $ "REVOKE CONNECT ON DATABASE \" { databaseName } \" FROM PUBLIC",
165+ "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity " +
166+ $ "WHERE datname = '{ databaseName } '",
167+ $ "DROP DATABASE \" { databaseName } \" "
168+ ) ;
149169 }
150170 return databaseNamesToDelete . Count ;
151171 }
152172
153173 //------------------------------------
154174 //private methods
155175
176+ private static void ExecuteScalars ( this string connectionString , params string [ ] commands )
177+ {
178+ using ( NpgsqlConnection conn = new NpgsqlConnection ( connectionString ) )
179+ {
180+ conn . Open ( ) ;
181+ foreach ( var commandText in commands )
182+ {
183+ using ( NpgsqlCommand cmd = new NpgsqlCommand ( commandText , conn ) )
184+ {
185+ var result = cmd . ExecuteScalar ( ) ;
186+ }
187+ }
188+ }
189+ }
190+
156191 private static DbContextOptionsBuilder < T > CreatePostgreSqlOptionWithDatabaseName < T > ( object callingClass ,
157192 string callingMember , Action < DbContextOptionsBuilder < T > > extraOptions )
158193 where T : DbContext
0 commit comments