c# - SQL Server Compact Edition 4 - AccessViolationException

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

最佳答案

这里的问题不是序列化对 DbContext 对象的访问,而是避免从不同线程访问同一对象。因此,解决方案是确保每次需要与数据库交互时都创建一个新的 DbContext 对象。

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

我不太确定您如何处理更新 UI。如果上面的代码在后台线程中运行,并且 UI 之前已绑定(bind)到 LogSubscription.Log 集合,则 UI 线程正在引用该集合的不同实例,您还必须将新条目添加到该集合。

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

更复杂的是延迟加载,在这种情况下,实体可能不会从数据库中加载,直到用户通过 UI 访问它们。要处理这个问题,您似乎必须在 UI 线程的生命周期内至少维护一个对 DbContext 的引用。

private static readonly SourceLogContext DbUILazyLoadContext = new SourceLogContext();

我欢迎对这些要点发表评论..

关于c# - SQL Server Compact Edition 4 - AccessViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11825209/

相关文章:

c# - EF4 中的数据加载策略/语法

java - 每个sql查询是否都需要在另一个线程中执行,如果不需要,在主线程上处理大约是多少?

python线程不会死

c# - 将域模型子计数投影到 View 模型上,无需额外查询

c# - 如何在datagridview中删除具有指定索引的行

c# - yield IEnumerable 的迭代器问题

java - Android - 发送大量请求的正确方法

.net - LINQ 查询与存储过程

c# - 如何使用 Linq 获取 IGrouping 索引到实体? (不支持异常)

c# - 来自程序集的资源作为流