DbContext不会发布SQLite数据库

时间:2013-06-07 08:34:28

标签: c# sqlite entity-framework-4 filelock file-move

首先,这些是我的意图:

  1. 在SQLite上创建DbContext
  2. 读取/写入
  3. 关闭背景
  4. 将文件移至其他位置
  5. 点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 个答案:

答案 0 :(得分:3)

我找到了另一个有同样问题的话题。在我重构了我的代码之后,我添加了

GC.Collect();

删除了文件锁,我可以移动文件。

请参阅:https://stackoverflow.com/a/14151917/2462736

答案 1 :(得分:0)

有两件事情在想:

  1. 确保Visual Studio未锁定数据库文件。打开服务器资源管理器,如果存在与文件的连接,请确保将其关闭或完全删除。
  2. 连接池很可能是连接打开的原因。禁用连接字符串中的池,如下所示:
  3. 数据来源= e:\ mydb.db;版本= 3; 合并=错误;

    Matt指出你应该使用 使用 语句,而不是手动调用dispose。这样,如果有异常,资源总是正确释放。