5

Ich baue eine .NET 4 WPF-Anwendung zuerst mit Entity Framework-Code und SQL Server Compact 4.0. Ich versuche DbContext.SaveChanges() auf einem Hintergrund-Thread rufen Sie die Benutzeroberfläche nicht blockiert, aber ich gelegentlich die folgende Ausnahme erhalten: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) 

Hier ist der Code, der SaveChanges() ruft:

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

Antwort

2

Die Frage ist nicht Zugriff auf das Objekt DbContext Serialisierung, wird es von verschiedenen Threads Zugriff auf das gleiche Objekt zu vermeiden. Die Lösung besteht also darin, sicherzustellen, dass Sie jedes Mal ein neues DbContext-Objekt erstellen, wenn Sie mit der Datenbank interagieren müssen.

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

Worüber ich nicht ganz sicher bin, ist, wie Sie mit der Aktualisierung der Benutzeroberfläche umgehen. Wenn der obige Code in einem Hintergrundthread ausgeführt wird und die Benutzeroberfläche zuvor an die Sammlung "LogSubscription.Log" gebunden war, verweist der UI-Thread auf eine andere Instanz der Sammlung, und Sie müssen den neuen Eintrag ebenfalls dieser Sammlung hinzufügen.

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

Eine weitere Komplikation ist ein träges Laden in dem Unternehmen möglicherweise nicht aus der Datenbank geladen werden, bis der Benutzer sich über die Benutzeroberfläche hat zugreifen. Um damit umzugehen es scheint, dass Sie mindestens einen Verweis auf die DbContext für die gesamte Lebensdauer des UI-Thread zu pflegen ..

private static readonly SourceLogContext DbUILazyLoadContext = new SourceLogContext(); 

Ich würde gern gesehen Kommentare zu diesen Punkten ..

+2

Haben Sie das Problem jemals gelöst? Ich habe ein ähnliches Problem. –

+0

Ich habe nicht wirklich ein besseres Verständnis als das, was ich in meiner Antwort habe. Sie können das Element, das zwei Sammlungen in der Methode [AddNewLogEntry] (https://github.com/tomhunter-gh/SourceLog/blob/aed3718af18fcff471f04c83f83a0160b97b6829/SourceLog.Model/LogSubscription.cs#L90) hinzugefügt wird, einmal im Kontext sehen Sammlung und einmal in die "UI-Sammlung". –

+0

Ich hatte das gleiche Problem, es endete damit, dass ich als Hintergrundarbeiter versuchte, auf den Kontext zuzugreifen, während andere Prozesse ihn nutzten. Ich habe diesen Anruf verschoben, nachdem die anderen Prozesse beendet waren und das es gelöst hat. Ich nehme an, dass es auch funktionieren würde, sie in die Warteschlange zu stellen. Soweit ich weiß, sollte EF das Threading verwalten, ich hatte nie ein solches Problem, bis ich den Hintergrundanruf erstellt habe. – Hannish

0

Ein Access tritt nur auf, wenn verifizierbarer verwalteter Code mit nicht verwaltetem Code oder mit unsicheren verwalteten Code interagiert.

Sie durch diesen Blog meine MS, wie gehen zu beheben hier Zugang 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

Danke, ich habe lese diesen Artikel. Ich benutze SQL CE 4.0 und wie der Artikel sagt "die Anwendung sollte den Zugriff auf diese Objekte serialisieren" habe ich 'lock' verwendet, um die Aufrufe von' SaveChanges() 'zu serialisieren .. –

+0

(aber ich bekomme immer noch den Fehler. .) –

Verwandte Themen