SQL Server Compact Edition 4 - AccessViolationException

时间:2012-08-06 08:58:35

标签: c# multithreading entity-framework sql-server-ce sql-server-ce-4

我正在使用Entity Framework代码和SQL Server Compact 4.0构建.NET 4 WPF应用程序。我试图在后台线程上调用DbContext.SaveChanges()以避免阻止UI,但我偶尔会遇到以下异常:

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 个答案:

答案 0 :(得分:2)

这里的问题不是序列化对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的引用。

private static readonly SourceLogContext DbUILazyLoadContext = new SourceLogContext();

我欢迎就这些问题发表评论。

答案 1 :(得分:0)

仅当可验证的托管代码与非托管代码或不安全的托管代码交互时,才会发生AccessViolationException。

你应该通过这个博客我的MS了解如何解决访问声音问题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