@@ -91,6 +91,39 @@ private sealed class NoSavePointTransaction(IRelationalConnection connection,
91
91
public override bool SupportsSavepoints => false ;
92
92
}
93
93
}
94
+
95
+ /// <see>https://www.postgresql.org/message-id/flat/141051591267657%40mail.yandex.ru</see>
96
+ /// <see>https://dba.stackexchange.com/questions/123145/how-to-view-tuples-changed-in-a-postgresql-transaction/123183#123183</see>
97
+ /// <see>https://stackoverflow.com/questions/49214219/what-is-the-meaning-of-epoch-in-txid-current-in-postgresql</see>
98
+ /// <see>https://github.com/npgsql/efcore.pg/issues/1035#issuecomment-2118584744</see>
99
+ protected class UseCurrentXactIdAsConcurrencyTokenCommandInterceptor : DbCommandInterceptor
100
+ {
101
+ public static UseCurrentXactIdAsConcurrencyTokenCommandInterceptor Instance => new ( ) ;
102
+
103
+ public override InterceptionResult < DbDataReader > ReaderExecuting (
104
+ DbCommand command ,
105
+ CommandEventData eventData ,
106
+ InterceptionResult < DbDataReader > result )
107
+ {
108
+ ManipulateCommand ( command ) ;
109
+ return result ;
110
+ }
111
+
112
+ public override ValueTask < InterceptionResult < DbDataReader > > ReaderExecutingAsync (
113
+ DbCommand command ,
114
+ CommandEventData eventData ,
115
+ InterceptionResult < DbDataReader > result ,
116
+ CancellationToken cancellationToken = default )
117
+ {
118
+ ManipulateCommand ( command ) ;
119
+ return new ( result ) ;
120
+ }
121
+
122
+ private static void ManipulateCommand ( DbCommand command ) =>
123
+ command . CommandText = command . CommandText . Replace (
124
+ "RETURNING xmin" ,
125
+ "RETURNING pg_current_xact_id()::xid" ) ;
126
+ }
94
127
}
95
128
public class TbmDbContext < TModelCacheKeyFactory > ( ILogger < TbmDbContext < TModelCacheKeyFactory > > logger )
96
129
: TbmDbContext ( logger )
@@ -113,6 +146,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder options)
113
146
options . UseNpgsql ( GetNpgsqlDataSource ( Config . GetConnectionString ( "Main" ) ) . Value , OnConfiguringNpgsql )
114
147
. ReplaceService < IModelCacheKeyFactory , TModelCacheKeyFactory > ( )
115
148
. ReplaceService < IRelationalTransactionFactory , NoSavePointTransactionFactory > ( )
149
+ . AddInterceptors ( UseCurrentXactIdAsConcurrencyTokenCommandInterceptor . Instance )
116
150
. UseCamelCaseNamingConvention ( ) ;
117
151
118
152
var dbSettings = Config . GetSection ( "DbSettings" ) ;
0 commit comments