5

私は、Entity FrameworkコードとSQ​​L Server Compact 4.0を使用して.NET 4 WPFアプリケーションを構築しています。私は、UIをブロック避けるために、バックグラウンドスレッドでDbContext.SaveChanges()を呼び出すようにしようとしているが、私は時折、次の例外を取得しています:SQL Server Compact Edition 4 - AccessViolationException

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(); 
     } 
    }); 
} 

答えて

2

ここでの問題は、それが別のスレッドから同じオブジェクトへのアクセスを避けることだDbContextオブジェクトへのアクセスをシリアル化されていないを解決する方法の私のMSのブログを経る必要があります

。したがって、解決策は、データベースと対話する必要があるたびに新しい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に少なくとも一つの基準を維持する必要があると思われるこの..

private static readonly SourceLogContext DbUILazyLoadContext = new SourceLogContext(); 

を扱うために、私はこれらの点についてのコメントを歓迎したい。..

+2

問題を解決しましたか?私にも同様の問題があります。 –

+0

私は私の答えにあるものよりも、より良い理解を得られませんでした。 [AddNewLogEntry](https://github.com/tomhunter-gh/SourceLog/blob/aed3718af18fcff471f04c83f83a0160b97b6829/SourceLog.Model/LogSubscription.cs#L90)メソッドで2つのコレクションに追加されているアイテムがコンテキストに1回ずつ表示されます一度「UIコレクション」に移動します。 –

+0

私は同じ問題を抱えていました。他のプロセスがコンテキストを使用している間にコンテキストにアクセスしようとするバックグラウンド作業者になってしまいました。私は、他のプロセスが終了してそれを解決した後、その呼び出しを移動しました。私はそれらをキューに入れても動作すると思います。私が知っている限り、EFはスレッドを管理する必要があります。バックグラウンドコールを作成するまで、私は決してそのような問題はありませんでした。 – Hannish

0

AccessViolationExceptionは、検証可能なマネージコードがアンマネージコードまたは安全でないマネージコードと相互作用する場合にのみ発生します。あなたはこのアクセスvoilation error: http://blogs.msdn.com/b/sqlservercompact/archive/2009/05/06/troubleshooting-access-violation-exception-while-using-sql-server-compact-database-with-ado-net-provider.aspx

+0

私がきたおかげで、その記事を読んでください。私はSQL CE 4.0を使用しており、「アプリケーションはこれらのオブジェクトへのアクセスをシリアライズする必要があります」と述べているので、 'SaveChanges()'への呼び出しを直列化するために 'lock'を使用しています.. –

+0

(ただし、 。) –

関連する問題