Salta ai contenuti

Moongate.Persistence

Persistenza PostgreSQL asincrona per entità identificate da seriale, basata su FreeSql.

Moongate.Persistence richiede .NET 10 e PostgreSQL. Usa la versione di Moongate disponibile nel feed NuGet configurato.

Terminal window
dotnet add package Moongate.Persistence

InitializeAsync apre e verifica ogni database di runtime configurato con SELECT 1, anche quando nessuna entità usa quella destinazione. Ogni successo registra Postgres connection successful; un errore genera un’eccezione prima che il sistema sia pronto. Le connessioni vengono verificate prima delle migrazioni o della sincronizzazione dello schema, e i database mancanti non vengono mai creati automaticamente. Il server configura solo le destinazioni del proprio ruolo: Accounts in login, Realm in game e entrambe in standalone. Una destinazione estranea alla configurazione del ruolo non viene contattata. Le integrazioni della libreria selezionano le proprie destinazioni in PostgreSqlPersistenceOptions.

  • Registrazione delle entità Auth/World con moduli interni e schemi PostgreSQL automatici.
  • Letture asincrone di entità scollegate, filtri tradotti in SQL, upsert ed eliminazioni.
  • Scritture raggruppate in una transazione asincrona per una singola destinazione database.
  • Verifiche di disponibilità dell’SQL versionato, anteprima dello schema proposto e sincronizzazione esplicita per lo sviluppo.
  • Generazione SQL per lo sviluppo attivabile esplicitamente, con file immutabili, esecuzione isolata e controlli di revisione persistenti.
  • Snapshot SaveAllAsync controllati dal proprietario per le entità attive gestite dall’applicazione.

Definisci una mappatura stabile tramite attributi in Player.cs. Lascia Id a zero per l’assegnazione automatica al primo UpsertAsync.

using FreeSql.DataAnnotations;
using Moongate.Core.Interfaces.Entities;
using Moongate.Core.Primitives;
[Table(Name = "sample_players.players")]
public sealed class Player : IMoongateEntity
{
[Column(Name = "id", IsPrimary = true, MapType = typeof(long))]
public Serial Id { get; set; }
[Column(Name = "name", StringLength = 100)]
public string Name { get; set; } = "";
}

Program.cs risolve la connessione durante l’esecuzione, applica esplicitamente lo schema di esempio, conferma due scritture insieme e legge un valore scollegato in modo asincrono. Imposta MOONGATE_PERSISTENCE_DATABASE su un URI di connessione postgres://user:password@host:5432/database per un database di sviluppo vuoto prima di eseguirlo.

using DryIoc;
using Moongate.Core.Primitives;
using Moongate.Persistence.Data.Config;
using Moongate.Persistence.Extensions;
using Moongate.Persistence.Interfaces;
using Moongate.Persistence.Services;
using Moongate.Persistence.Types.Persistence;
var connectionString = Environment.GetEnvironmentVariable("MOONGATE_PERSISTENCE_DATABASE")
?? throw new InvalidOperationException("Set MOONGATE_PERSISTENCE_DATABASE before running this example.");
var options = new PostgreSqlPersistenceOptions(
[new PersistenceDatabaseOptions(PersistenceDatabaseTarget.Realm, connectionString)],
autoSynchronizeSchema: true);
using var container = new Container();
container.RegisterMoongatePersistence(options)
.AddPersistenceWorld<Player>();
await using var persistence = container.Resolve<MoongatePersistenceService>();
await persistence.InitializeAsync();
var mario = new Player { Name = "Mario" };
await persistence.ExecuteInTransactionAsync(PersistenceDatabaseTarget.Realm, async transaction =>
{
var players = transaction.GetDataAccess<Player>();
await players.UpsertAsync(mario);
await players.UpsertAsync(new Player { Name = "Luigi" });
});
var player = await container.Resolve<IDataAccess<Player>>().GetByIdAsync(mario.Id);
Console.WriteLine(player?.Name);

AddPersistenceWorld<T>() seleziona il database Realm; AddPersistenceAuth<T>() seleziona il database Accounts condiviso. Moongate crea i moduli interni dagli attributi di tabella qualificati con lo schema, quindi non è richiesta una classe di modulo. Entrambi gli helper accettano anche una sorgente attiva e una funzione esplicita di snapshot scollegato. Le dichiarazioni esplicite IPersistenceModule rimangono disponibili per i plugin che ne hanno bisogno.

Le opzioni di connessione accettano URI postgres:// e postgresql://, comprese credenziali con codifica percentuale, host IPv6 e opzioni di query come sslmode e connect_timeout. Sono supportate anche le stringhe di connessione native Npgsql.

Le distribuzioni ordinarie mantengono disabilitata la sincronizzazione automatica. Genera e revisiona l’SQL versionato, poi applicalo con il comando mgctl migrate apply. Configura PostgreSqlPersistenceOptions.MigrationCatalogFactory per le verifiche delle migrazioni necessarie in un host personalizzato; mgserver (il progetto Moongate.Server) lo collega automaticamente. SynchronizeSchemaAsync rimane una comodità riservata allo sviluppo e non registra la cronologia.

Le letture restituiscono entità scollegate. Modificare un’istanza restituita non la salva; chiama UpsertAsync o DeleteAsync. Nelle scritture prevale l’ultimo scrittore e non è previsto un token di concorrenza ottimistica. Un callback di transazione copre una sola destinazione Accounts o Realm e non viene mai ritentato dopo un risultato di commit incerto.

Un Id pari a zero su UpsertAsync viene assegnato da una sequenza PostgreSQL gestita dalle migrazioni e riscritto tramite il setter pubblico Id dell’entità. Gli ID diversi da zero vengono conservati. Le sequenze sono per tabella, condivise tra processi e limitate all’intervallo uint diverso da zero; non allocano gli intervalli UO dei mobile/oggetti. Il ruolo di runtime richiede USAGE sulla sequenza e SELECT affinché l’esportazione dei dati ne conservi i valori. Gli inserimenti falliti ripristinano zero; un successivo rollback della transazione conserva un ID assegnato. Le prenotazioni non vengono mai recuperate. Le nuove entità non richiedono nomi di sequenza nei propri servizi.

SaveAllAsync richiede ID diversi da zero già assegnati; salva prima le nuove entità con UpsertAsync. Acquisisce le sorgenti attive registrate e conferma una transazione indipendente per destinazione database. Le funzioni di snapshot devono copiare in profondità lo stato mutabile annidato. Un’entità assente viene conservata; l’eliminazione è sempre esplicita. Vengono scritti solo gli snapshot la cui impronta (i primi 128 bit dello SHA-256 del loro JSON) è cambiata dall’ultimo salvataggio confermato; il primo salvataggio e ogni dodicesimo scrivono tutto.

FreeSql può generare normale DDL additivo dello schema. Usa OldName per le rinomine supportate e scrivi SQL esplicito revisionato per le trasformazioni semantiche dei dati. I downgrade sono gestiti dall’operatore. IPersistenceDataExporter.ExportDataAsync scrive i dati di un database come uno script COPY che psql può ripristinare; pianificare e ruotare i file è compito del server.

Gli oggetti personalizzati e List<T> possono usare [JsonMap, Column(DbType = "jsonb", IsNullable = true)] da FreeSql.DataAnnotations. Questo pacchetto include e abilita FreeSql.Extensions.JsonMap per entrambe le destinazioni, usando Newtonsoft.Json. Con le impostazioni predefinite, i membri JSON conservano i nomi C#; il nome della colonna SQL segue comunque snake_case. Le liste vuote vengono salvate e rilette come [], le proprietà nullable come SQL NULL. Gli upsert sostituiscono il valore JSON completo e le letture rimangono scollegate. Gli snapshot del salvataggio del mondo devono copiare in profondità le collezioni e i loro elementi mutabili. Vedi il tutorial JSONB.

Le altre proprietà complesse richiedono ancora una mappatura supportata di colonna/navigazione oppure l’omissione esplicita con IsIgnore. Un grafo di oggetti privo di annotazioni non viene serializzato né elaborato in cascata implicitamente. Le modifiche al contenuto JSON non migrano automaticamente i documenti esistenti.

Le mappature sono immutabili, basate solo su attributi e identiche ovunque per un tipo CLR persistente. I moduli selezionano proprietà e destinazione; non rimappano i tipi. Non riconfigurare autonomamente questi tipi tramite un’altra istanza FreeSql grezza. Il confronto dello schema FreeSql confronta il database attuale con gli attributi attuali. L’SQL versionato e il registro dei checksum risiedono in Moongate.Persistence.Migrations; il runner separato li applica atomicamente.

FreeSql.Provider.PostgreSQL 3.5.311 risolve attualmente Npgsql 5.0.18. Questa limitazione nota del provider non deve essere nascosta con una sostituzione silenziosa della versione principale di Npgsql. Aggiorna la combinazione provider/driver solo dopo aver eseguito i test di compatibilità PostgreSQL.

Vedi la guida alla persistenza e alle operazioni per revisione dello schema, proprietà dei plugin, salvataggi del mondo, transazioni e responsabilità del backup dei database.

Il server supporta persistence.auto_generate_migrations = true insieme a una persistence.migrations_directory esplicita. Scrive e applica SQL additivo all’avvio; le modifiche non sicure o non supportate rimangono contrassegnate per la revisione. Questa modalità è disattivata per impostazione predefinita e non può essere combinata con auto_sync_schema. Gli indici semplici sulle colonne, compresi gli indici univoci e compositi, sono automatici solo sulle tabelle create nella stessa migrazione. Gli indici su tabelle esistenti e le espressioni o opzioni di indice non supportate richiedono revisione.

Le integrazioni autonome della libreria possono fornire DevelopmentMigrationOptions con un’implementazione di IDevelopmentMigrationRunner e un resolver esplicito dei componenti. Mantieni l’esecuzione delle migrazioni isolata dal driver PostgreSQL di FreeSql. Vedi la guida alle migrazioni di sviluppo.

Distribuito con licenza AGPL-3.0-or-later. Vedi il repository dei sorgenti e la licenza.

Creato con ❤️ da Tom

Offrimi un caffè