Omni Networking uses customized versions of SQLKata and Dapper modified for Unity:
Improved:
✨ Reduced memory allocations and garbage collector pressure
🔄 Async/await support with Task/ValueTask/UniTask
⚡ Added support for IL2CPP compilation
These modifications ensure better performance and compatibility within Unity's ecosystem while maintaining the original libraries' ease of use.
IL2CPP Compatibility
Some database features may have limited compatibility when using IL2CPP compilation. However, all essential functionality remains available through alternative approaches supported by the Omni Networking framework.
The Omni Networking database module can currently only be used on the server side. Attempts to use database functionality on the client will result in errors.
In the future, we plan to add support for local database operations on the client side, especially for databases like SQLite, enabling persistent offline data storage.
Microsoft's enterprise database system with advanced security features, high scalability, and deep integration with other Microsoft products. Ideal for large-scale multiplayer game backends.
✅
MariaDB
Enhanced MySQL fork with better performance, additional storage engines, and stronger community focus. Great for web applications and multiplayer games requiring high transaction rates.
✅
MySQL
Popular relational database system optimized for web applications and online games with excellent cost-efficiency and widespread hosting support.
✅
PostgreSQL
Advanced open-source database with robust JSON support, extensibility, and geospatial features. Recommended for complex game systems requiring sophisticated data structures.
✅
Oracle
Enterprise-grade database system with unmatched reliability, security, and performance for mission-critical applications with high concurrent user loads.
✅
SQLite
Self-contained, serverless SQL database engine perfect for client-side storage, mobile devices, and embedded systems where a full database server isn't needed.
✅
Firebird
Open-source relational database with multi-generational architecture, excellent referential integrity, and small footprint. Well-suited for distributed applications and game analytics.
publicclassMyDatabaseManager:DatabaseManager{protectedoverridevoidOnStart(){// Configure database connection using type and connection stringvarcredentials=newDbCredentials(DatabaseType.MySql,"localhost","mydb","user","password");SetDatabase(credentials);}}
Automatic Security in Builds
The SetConnectionString method is automatically stripped from non-server builds in release mode. This ensures database credentials are not included in client builds, enhancing your application's security.
// Good: Parameterized queryawaitbuilder.Where("status","=",userInput).FirstAsync();// Bad: String concatenationvarquery=$"SELECT * FROM users WHERE status = '{userInput}'";
// Validate input before database operationsif(!IsValidUserInput(userInput)){thrownewArgumentException("Invalid input");}// Use strong typingpublicclassUser{[Required][StringLength(50)]publicstringName{get;set;}[EmailAddress]publicstringEmail{get;set;}}
// Implement row-level securitypublicclassSecureDatabaseManager:DatabaseManager{protectedoverrideasyncTask<DatabaseConnection>GetConnectionAsync(){varconn=awaitbase.GetConnectionAsync();// Set user context for row-level securityawaitconn.RunAsync("SET SESSION app.current_user_id = @userId",new{userId=GetCurrentUserId()});returnconn;}}
// Use appropriate indexesawaitbuilder.Where("status","=","active").OrderBy("created_at")// Ensure index exists on created_at.GetAsync<User>();// Limit result setsawaitbuilder.Where("status","=","active").Limit(100)// Prevent large result sets.GetAsync<User>();
// Properly dispose connectionsusing(varconn=awaitGetConnectionAsync()){// Use connection}// Use connection poolingSetDatabase(newDbCredentials{ConnectionString="Pooling=true;MinPoolSize=5;MaxPoolSize=100;"});
publicclassDatabaseBackup{publicasyncTaskCreateBackupAsync(){usingvardb=awaitGetConnectionAsync();awaitdb.RunAsync("BACKUP DATABASE MyDB TO DISK = 'backup.bak'");}}
publicclassDatabaseRecovery{publicasyncTaskRestoreFromBackupAsync(DateTimepointInTime){usingvardb=awaitGetConnectionAsync();awaitdb.RunAsync("RESTORE DATABASE MyDB FROM DISK = 'backup.bak' WITH RECOVERY, STOPAT = @pointInTime",new{pointInTime});}}
// Get first record without mappingvaruser=awaitbuilder.Where(new{id=1}).FirstAsync();// Get first record with mapping to User classvaruser=awaitbuilder.Where(new{id=1}).FirstAsync<User>();// Get first record with specific columnsvaruser=awaitbuilder.Select("id","name","email").Where(new{id=1}).FirstAsync<User>();
// Get all records without mappingvarusers=awaitbuilder.AllAsync();// Get all records with mapping to User classvarusers=awaitbuilder.AllAsync<User>();// Get all records with specific columnsvarusers=awaitbuilder.Select("id","name","email").AllAsync<User>();
// Insert single recordawaitbuilder.InsertAsync(newUser{Name="John",Email="john@example.com"});// Insert and get IDvarid=awaitbuilder.InsertGetIdAsync<int>(newUser{Name="John",Email="john@example.com"});
// Check if record existsvarexists=awaitbuilder.Where(new{id=1}).ExistsAsync();// Check if any records match conditionvarexists=awaitbuilder.Where("status","=","active").ExistsAsync();
// Count recordsvarcount=awaitbuilder.CountAsync<int>();// Sum valuesvartotal=awaitbuilder.SumAsync<int>("points");// Average valuesvaravg=awaitbuilder.AverageAsync<double>("score");// Min/Max valuesvarmin=awaitbuilder.MinAsync<int>("age");varmax=awaitbuilder.MaxAsync<int>("age");
// Process records in chunksawaitbuilder.ChunkAsync(100,async(users,page)=>{foreach(varuserinusers){// Process each user}returntrue;// Continue to next chunk});
// Execute raw SQLvarusers=awaitconn.Connection.QueryAsync<User>("SELECT * FROM users WHERE status = @status",new{status="active"});// Execute stored procedurevarresult=awaitconn.Connection.QueryAsync<User>("sp_get_user",new{userId=1},commandType:CommandType.StoredProcedure);
// Build complex queriesvarquery=builder.Select("users.*","profiles.bio").Join("profiles","users.id","profiles.user_id").Where("users.status","=","active").Where("profiles.verified","=",true).OrderBy("users.created_at","desc").Limit(10);// Get raw SQLvarsql=query.ToSql();// Execute queryvarresults=awaitquery.GetAsync<User>();