5

最初に Entity Framework コードと SQL Server Compact 4.0 を使用して .NET 4 WPF アプリケーションを構築しています。UI のブロックを回避するためにバックグラウンド スレッドを呼び出そうとしてDbContext.SaveChanges()いますが、次の例外が発生することがあります。

System.AccessViolationException occurred
  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Source=System.Data.SqlServerCe
  StackTrace:
       at System.Data.SqlServerCe.NativeMethodsHelper.OpenStore(IntPtr pOpenInfo, IntPtr pfnOnFlushFailure, IntPtr& pStoreService, IntPtr& pStoreServer, IntPtr& pQpServices, IntPtr& pSeStore, IntPtr& pTx, IntPtr& pQpDatabase, IntPtr& pQpSession, IntPtr& pStoreEvents, IntPtr& pError)
       at System.Data.SqlServerCe.NativeMethods.OpenStore(IntPtr pOpenInfo, IntPtr pfnOnFlushFailure, IntPtr& pStoreService, IntPtr& pStoreServer, IntPtr& pQpServices, IntPtr& pSeStore, IntPtr& pTx, IntPtr& pQpDatabase, IntPtr& pQpSession, IntPtr& pStoreEvents, IntPtr& pError)
       at System.Data.SqlServerCe.SqlCeConnection.Open(Boolean silent)
       at System.Data.SqlServerCe.SqlCeConnection.Open()
       at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
       at System.Data.EntityClient.EntityConnection.Open()
       at System.Data.Objects.ObjectContext.EnsureConnection()
       at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
       at System.Data.Entity.Internal.InternalContext.SaveChanges()
       at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
       at System.Data.Entity.DbContext.SaveChanges()
       at SourceLog.Model.LogSubscriptionManager.<SaveChanges>b__2() in C:\github.com\tomhunter-gh\SourceLog\SourceLog.Model\LogSubscriptionManager.cs:line 51
  InnerException: (null)

を呼び出すコードは次のSaveChanges()とおりです。

internal static readonly object DbSaveLockObject = new object();
public static void SaveChanges()
{
    Task.Factory.StartNew(() =>
    {
        lock (DbSaveLockObject)
        {
            Debug.WriteLine(DateTime.Now + ": SaveChanges in lock");
            Db.SaveChanges();
        }
    });
}
4

2 に答える 2

3

ここでの問題は、DbContext オブジェクトへのアクセスをシリアル化することではなく、異なるスレッドから同じオブジェクトへのアクセスを回避することです。したがって、解決策は、データベースと対話する必要があるたびに新しい DbContext オブジェクトを作成することです。

using (var db = new SourceLogContext())
{
    db.LogSubscriptions.First(s => s.LogSubscriptionId == LogSubscriptionId)
        .Log.Add((LogEntry)e.LogEntry);
    db.SaveChanges();
}

私がよくわからないのは、UI の更新をどのように処理するかです。上記のコードがバックグラウンド スレッドで実行されていて、UI が以前に LogSubscription.Log コレクションにバインドされている場合、UI スレッドはコレクションの別のインスタンスを参照しているため、このコレクションにも新しいエントリを追加する必要があります。

_uiThread.Post(entry => Log.Add((LogEntry)entry), e.LogEntry);

さらに複雑なのは、ユーザーが UI を介してエンティティにアクセスするまでデータベースからエンティティが読み込まれない可能性がある遅延読み込みです。これを処理するには、UI スレッドの存続期間中、DbContext への参照を少なくとも 1 つ維持する必要があるようです。

private static readonly SourceLogContext DbUILazyLoadContext = new SourceLogContext();

これらの点についてのコメントを歓迎します..

于 2012-08-09T21:53:44.117 に答える
0

AccessViolationException は、検証可能なマネージド コードがアンマネージド コードまたは安全でないマネージド コードと対話する場合にのみ発生します。

アクセス違反エラーのトラブルシューティング方法については、MS のこのブログを参照する必要があります。 sql-server-compact-database-with-ado-net-provider.aspx

于 2012-08-06T09:10:46.643 に答える