【发布时间】:2013-06-07 08:34:28
【问题描述】:
首先,这是我的意图:
- 在 SQLite 上创建 DbContext
- 对其进行读写
- 关闭上下文
- 将文件移动到其他位置
第 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 重构
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();
}
【问题讨论】:
-
你能展示你的实际代码吗,所以一切都在同一个块中(我的意思是,由于上下文生命周期,更容易看到实际的执行流程)?
-
@ken2k 完成。你需要更多吗?
-
什么是
SqlLiteContext?它是否封装了实体框架上下文? -
一个想法:有没有类似 SQLite 的连接池的东西?在这种情况下,请关闭它。
-
您应该更喜欢使用“使用”而不是手动调用 Dispose。如果有任何抛出(初始化程序和 Dispose 之间的任何调用),它将不会通过 SqlLiteContext 调用 Dispose。尝试一下,看看该行为是否与直接调用 Dispose 不同——它对如何调用内部受保护方法 Dispose(bool) 的解析可能不同。
标签: c# sqlite entity-framework-4 filelock file-move