9

まず、これらは私の意図です:

  1. SQLite で DbContext を作成する
  2. 読み書きする
  3. コンテキストを閉じる
  4. ファイルを別の場所に移動する

ポイント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();
}
4

2 に答える 2

3

同じ問題を抱えた別のトピックを見つけました。コードをリファクタリングした後、追加しました

GC.Collect();

これでファイルロックが解除され、ファイルを移動できました。

参照: https://stackoverflow.com/a/14151917/2462736

于 2013-06-23T18:02:35.543 に答える
1

次の 2 つのことが思い浮かびます。

  1. Visual Studio がデータベース ファイルをロックしていないことを確認します。サーバー エクスプローラーを開き、ファイルへの接続がある場合は、ファイルが閉じられているか完全に削除されていることを確認します。
  2. 接続プーリングが接続を開いたままにしている可能性があります。次のように、接続文字列でプーリングを無効にします。

データ ソース=e:\mydb.db;バージョン=3; プーリング=偽

Matt が指摘したように、dispose を手動で呼び出すのではなく、 usingステートメントを実際に使用する必要があります。そうすれば、例外が発生した場合でも、リソースは常に適切に解放されます。

于 2013-06-18T07:24:12.970 に答える