DbContext не выпускает базу данных SQLite
Во-первых, это мои намерения:
- Создайте DbContext на SQLite
- Читай и пиши из / в него
- Закрыть контекст
- Переместить файл в другое место
Пункты 1-3 работают отлично. Проблема начинается, когда я пытаюсь переместить базу данных. Я получаю сообщение об ошибке, в котором говорится:
'The process cannot access the file because it is being used by another process.'
Как я могу решить это?
Сначала я создаю контекст. Я должен использовать это в нескольких методах, и я не хочу создавать это каждый раз, когда мне это нужно. Так что я храню это как член.
_sqliteContext = new SqlLiteContext(sqliteContextName);
Затем я хочу получить доступ к таблице с именем sync
и получите свою последнюю запись.
var sync = _sqliteContext.Syncs.OrderByDescending(s => s.Date);
_lastSync = sync.Any() ? sync.First().Date : new DateTime(0);
Вот и все. Затем я закрываю контекст.
_sqliteContext.Dispose();
И попробуйте переместить файл.
File.Move(sqliteUploadLocation, sqliteDownloadLocation);
Вот где я получаю исключение.
Когда я заменяю выделение вставкой, вроде следующего:
var sync = new Sync { Id = Guid.NewGuid().ToString(), Date = DateTime.Now };
_sqliteContext.Syncs.Add(sync);
_sqliteContext.SaveChanges();
Это работает, и я могу переместить базу данных. Есть идеи, почему мой выбор не снимает блокировку?
Обновить
// Start synchronisation.
new SyncManager(mssqlString, sqliteUploadLocation).Start();
// Move file from upload to download location.
try
{
File.Move(sqliteUploadLocation, sqliteDownloadLocation);
}
catch (Exception ex)
{
Console.WriteLine("Moving failed!");
Console.WriteLine(ex.Message);
}
public void Start()
{
// Create connection string for the sqlite database.
const string sqliteContextName = "SqLiteContext";
var sqliteConnStringSettings = new ConnectionStringSettings
{
Name = sqliteContextName,
ConnectionString = "Data Source=" + _sqliteUploadLocation + ";Version=3;BinaryGUID=False;",
ProviderName = "System.Data.SQLite"
};
// Read configuration, delete available connection strings and add ours.
var conf = ConfigurationManager.OpenMachineConfiguration();
var connStrings = conf.ConnectionStrings;
connStrings.ConnectionStrings.Remove(sqliteContextName);
connStrings.ConnectionStrings.Add(sqliteConnStringSettings);
try
{
conf.Save(ConfigurationSaveMode.Minimal);
}
catch (Exception)
{
// Insufficient rights to save.
return;
}
ConfigurationManager.RefreshSection("connectionStrings");
// Create connection to the sqlite database.
_sqliteContext = new SqlLiteContext(sqliteContextName);
// Create connection to the mssql database.
_mssqlContext = new MsSqlContext(_mssqlConnString);
// Read last sync date.
var sync = _sqliteContext.Syncs.OrderByDescending(s => s.Date);
_lastSync = sync.Any() ? sync.First().Date : new DateTime(0);
// Synchronize tables.
//SyncTablePerson();
//SyncTableAddressAllocation();
// Creates an entry for this synchronisation.
CreateSyncEntry();
// Release resources.
_sqliteContext.Dispose();
_mssqlContext.Dispose();
}
private void CreateSyncEntry()
{
var sync = new Sync { Id = Guid.NewGuid().ToString(), Date = DateTime.Now };
_sqliteContext.Syncs.Add(sync);
_sqliteContext.SaveChanges();
}
Обновление 2
public class SqlLiteContext : Context
{
public DbSet<Sync> Syncs { get; set; }
public SqlLiteContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer(new NoOperationStrategy<SqlLiteContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new PersonConfig());
modelBuilder.Configurations.Add(new AddressAllocationConfig());
modelBuilder.Configurations.Add(new AddressConfig());
modelBuilder.Configurations.Add(new SyncConfig());
}
}
public class NoOperationStrategy<T> : IDatabaseInitializer<T> where T : DbContext
{
public void InitializeDatabase(T context)
{
}
}
public abstract class Context : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<AddressAllocation> AddressAllocations { get; set; }
public DbSet<Address> Addresses { get; set; }
protected Context(string connectionString)
: base(connectionString)
{
}
}
Рефакторинг с использованием
using (var sqliteContext = new SqlLiteContext(_sqliteContextName))
{
// Read last sync date.
var sync = sqliteContext.Syncs.Select(s => s).OrderByDescending(s => s.Date);
var lastSync = sync.Any() ? sync.First().Date : new DateTime(1900, 1, 1);
using (var mssqlContext = new MsSqlContext(_mssqlConnString))
{
SyncTablePerson(sqliteContext, mssqlContext, lastSync);
SyncTableAddressAllocation(sqliteContext, mssqlContext, lastSync);
// Save server changes.
mssqlContext.SaveChanges();
}
// Creates an entry for this synchronisation.
sqliteContext.Syncs.Add(new Sync { Id = Guid.NewGuid().ToString(), Date = DateTime.Now });
// Save local changes.
sqliteContext.SaveChanges();
}
2 ответа
Я нашел другую тему с той же проблемой. После рефакторинга своего кода я добавил
GC.Collect();
Это сняло блокировку файла, и я мог переместить файл.
На ум приходят две вещи:
- Убедитесь, что Visual Studio не блокирует файл базы данных. Откройте Обозреватель серверов и, если есть соединение с файлом, убедитесь, что он закрыт или вообще удален.
- Вероятно, что пул соединений - это то, что удерживает соединение открытым. Отключите пул в строке подключения следующим образом:
Источник данных =e:\mydb.db; Версия =3;Объединение = Ложь;
Как указал Мэтт, вам действительно следует использовать оператор using, а не вызывать dispose вручную. Таким образом, если есть исключение, ресурсы всегда высвобождаются правильно.