/// <summary> /// Install the initial catalog /// </summary> public bool Install() { var search = ApplicationContext.Current?.ConfigurationManager.GetConnectionString("santeDbSearch"); LockableSQLiteConnection db = null; // Database for the SQL Lite connection if (search != null) { db = SQLiteConnectionManager.Current.GetReadWriteConnection(search); using (db.Lock()) this.Install(db); } db = SQLiteConnectionManager.Current.GetReadWriteConnection(ApplicationContext.Current?.ConfigurationManager.GetConnectionString(ApplicationContext.Current?.Configuration.GetSection <DcDataConfigurationSection>().MainDataSourceConnectionStringName)); using (db.Lock()) return(this.Install(db)); }
/// <summary> /// Get or create audit code /// </summary> private DbAuditCode GetOrCreateAuditCode(LockableSQLiteConnection context, AuditCode messageCode) { if (messageCode == null) { return(null); } var existing = context.Table <DbAuditCode>().Where(o => o.Code == messageCode.Code && o.CodeSystem == messageCode.CodeSystem).FirstOrDefault(); if (existing == null) { byte[] codeId = Guid.NewGuid().ToByteArray(); var retVal = new DbAuditCode() { Code = messageCode.Code, CodeSystem = messageCode.CodeSystem, Id = codeId }; context.Insert(retVal); return(retVal); } else { return(existing); } }
/// <summary> /// Local data context /// </summary> public LocalDataContext(LockableSQLiteConnection connection) { this.Connection = connection; this.m_cacheCommit = new Dictionary <Guid, IdentifiedData>(); }
/// <summary> /// Local data context /// </summary> public SQLiteDataContext(LockableSQLiteConnection connection, IPrincipal principal) { this.Principal = principal; this.Connection = connection; this.m_cacheCommit = new Dictionary <Guid, IdentifiedData>(); }
/// <summary> /// Bundles are special, they may be written on the current connection /// or in memory /// </summary> public override Bundle Insert(Bundle data, TransactionMode mode, IPrincipal principal) { // first, are we just doing a normal insert? if (data.Item.Count <= 250) { return(base.Insert(data, mode, principal)); } else { // It is cheaper to open a mem-db and let other threads access the main db for the time being base.FireInserting(new DataPersistingEventArgs <Bundle>(data, mode, principal)); var cstr = ApplicationContext.Current.ConfigurationManager.GetConnectionString("santeDbData"); // Memory connection using (var memConnection = new LockableSQLiteConnection(ApplicationContext.Current.GetService <ISQLitePlatform>(), new SanteDB.Core.Configuration.Data.ConnectionString() { Value = "dbfile=:memory:" }, SQLiteOpenFlags.ReadWrite)) { try { ApplicationContext.Current.SetProgress(Strings.locale_prepareBundle, 0.5f); // We want to apply the initial schema new SanteDB.DisconnectedClient.SQLite.Configuration.Data.Migrations.InitialCatalog().Install(memConnection, true); // Copy the name component and address component values if (cstr.GetComponent("encrypt") != "true" || ApplicationContext.Current.GetCurrentContextSecurityKey() == null) { memConnection.Execute($"ATTACH DATABASE '{cstr.GetComponent("dbfile")}' AS file_db KEY ''"); } else { memConnection.Execute($"ATTACH DATABASE '{cstr.GetComponent("dbfile")}' AS file_db KEY X'{BitConverter.ToString(ApplicationContext.Current.GetCurrentContextSecurityKey()).Replace("-", "")}'"); } try { memConnection.BeginTransaction(); //// Names & Address memConnection.Execute($"INSERT OR REPLACE INTO phonetic_value (uuid, value) SELECT uuid, value FROM file_db.phonetic_value"); memConnection.Execute($"INSERT OR REPLACE INTO entity_addr_val (uuid, value) SELECT uuid, value FROM file_db.entity_addr_val"); //foreach (var itm in memConnection.Query<String>("SELECT NAME FROM SQLITE_MASTER WHERE TYPE = 'index' AND SQL IS NOT NULL")) // memConnection.Execute(String.Format("DROP INDEX {0};", itm)); memConnection.Commit(); } catch (Exception e) { memConnection.Rollback(); throw new DataException("Error inserting bundle", e); } memConnection.Execute("DETACH DATABASE file_db"); // We insert in the memcontext now using (var memContext = new SQLiteDataContext(memConnection, principal)) this.InsertInternal(memContext, data); var columnMapping = memConnection.TableMappings.Where(o => o.MappedType.Namespace.StartsWith("SanteDB")).ToList(); // Now we attach our local file based DB by requesting a lock so nobody else touches it! using (var fileContext = this.CreateConnection(principal)) using (fileContext.LockConnection()) { if (cstr.GetComponent("encrypt") != "true" || ApplicationContext.Current.GetCurrentContextSecurityKey() == null) { memConnection.Execute($"ATTACH DATABASE '{cstr.GetComponent("dbfile")}' AS file_db KEY ''"); } else { memConnection.Execute($"ATTACH DATABASE '{cstr.GetComponent("dbfile")}' AS file_db KEY X'{BitConverter.ToString(ApplicationContext.Current.GetCurrentContextSecurityKey()).Replace("-", "")}'"); } try { memConnection.BeginTransaction(); // Copy copy!!! int i = 0; foreach (var tbl in memConnection.Query <SysInfoStruct>("SELECT name FROM sqlite_master WHERE type='table'")) { memConnection.Execute($"INSERT OR REPLACE INTO file_db.{tbl.Name} SELECT * FROM {tbl.Name}"); ApplicationContext.Current.SetProgress(Strings.locale_committing, (float)i++ / columnMapping.Count); } ApplicationContext.Current.SetProgress(Strings.locale_committing, 1.0f); memConnection.Commit(); } catch { memConnection.Rollback(); throw; } } } catch (Exception e) { this.m_tracer.TraceWarning("Error inserting bundle using fast insert method - Will use slow method: {0}", e); return(base.Insert(data, mode, principal)); // Attempt to do a slow insert // TODO: Figure out why the copy command sometimes is missing UUIDs //throw new LocalPersistenceException(Synchronization.Model.DataOperationType.Insert, data, e); } } base.FireInserted(new DataPersistedEventArgs <Bundle>(data, mode, principal)); return(data); } }