5

Tôi đang xây dựng một ứng dụng .NET 4 WPF bằng mã Entity Framework đầu tiên và SQL Server Compact 4.0. Tôi đang cố gắng để gọi DbContext.SaveChanges() trên một sợi nền để tránh chặn các giao diện người dùng, nhưng tôi thỉnh thoảng nhận được ngoại lệ sau đây: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) 

Dưới đây là đoạn code mà các cuộc gọi 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(); 
     } 
    }); 
} 

Trả lời

2

Vấn đề ở đây là không serializing truy cập vào các đối tượng DbContext, nó tránh truy cập vào cùng một đối tượng từ chủ đề khác nhau. Vì vậy, giải pháp là để đảm bảo bạn tạo một đối tượng DbContext mới mỗi lần bạn cần tương tác với cơ sở dữ liệu.

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

Điều tôi không chắc chắn về cách bạn xử lý cập nhật giao diện người dùng. Nếu mã ở trên đang chạy trong một chuỗi nền và giao diện người dùng trước đó đã bị ràng buộc vào bộ sưu tập LogSubscription.Log, thì chuỗi giao diện người dùng đang tham chiếu một phiên bản khác của bộ sưu tập và bạn cũng phải thêm mục nhập mới vào bộ sưu tập này.

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

Một biến chứng nữa là tải chậm nơi thực thể không được tải từ cơ sở dữ liệu cho đến khi người dùng truy cập chúng thông qua giao diện người dùng. Để xử lý điều này có vẻ như bạn phải duy trì ít nhất một tham chiếu đến DbContext cho cuộc sống của thread UI ..

private static readonly SourceLogContext DbUILazyLoadContext = new SourceLogContext(); 

tôi muốn chào đón ý kiến ​​về những điểm này ..

+2

Bạn đã từng giải quyết vấn đề chưa? Tôi có một vấn đề tương tự. –

+0

Tôi không thực sự hiểu rõ hơn những gì tôi có trong câu trả lời của mình. Bạn có thể xem mục đang được thêm vào hai bộ sưu tập trong phương pháp [AddNewLogEntry] (https://github.com/tomhunter-gh/SourceLog/blob/aed3718af18fcff471f04c83f83a0160b97b6829/SourceLog.Model/LogSubscription.cs#L90), một lần vào ngữ cảnh thu thập và một lần vào "bộ sưu tập giao diện người dùng". –

+0

Tôi đã có cùng một vấn đề, nó đã kết thúc được một backgroundworker cố gắng truy cập vào bối cảnh trong khi các quá trình khác đang sử dụng nó. Tôi đã chuyển cuộc gọi đó sau khi các quá trình khác kết thúc và giải quyết nó. Tôi đoán rằng xếp hàng họ cũng sẽ làm việc. Theo như tôi biết EF nên quản lý luồng, tôi chưa bao giờ gặp vấn đề như vậy cho đến khi tôi tạo cuộc gọi nền. – Hannish

0

Một AccessViolationException chỉ xảy ra khi mã được quản lý có thể xác minh tương tác với mã không được quản lý hoặc với mã được quản lý không an toàn.

Bạn nên đi qua blog này MS của tôi về cách khắc phục sự cố truy cập 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

Cảm ơn, tôi đã đọc bài viết đó. Tôi đang sử dụng SQL CE 4.0 và như bài báo nói "ứng dụng nên serialize quyền truy cập vào các đối tượng này" Tôi đã sử dụng 'lock' để sắp xếp các cuộc gọi đến' SaveChanges() '.. –

+0

(nhưng tôi vẫn gặp lỗi. .) –

Các vấn đề liên quan