2013-05-22 34 views
8

Tôi có thử nghiệm đơn vị rất đơn giản sau đây tái tạo một trường hợp mà DbContext.SaveChanges không phải là nguyên tử. Bởi không nguyên tử tôi có nghĩa là dữ liệu cam kết có thể được đọc trước khi tất cả các cam kết đã được hoàn thành.Mã khung thực thể đầu tiên: SaveChanges không phải là nguyên tử

Thêm công việc: Trong một vòng lặp, hãy thêm một TestEntity mới và một tham chiếu tính xác thực. Xác thực tác vụ: kiểm tra nếu có một TestEntity không được tham chiếu bởi bất kỳ tham chiếu nào - điều đó không được cho là xảy ra vì cách tôi thêm các thực thể.

Kiểm tra đơn vị không thành công ... bất kỳ lời khuyên nào?

EDIT: Theo câu trả lời chấp nhận - Để chạy thử nghiệm đơn vị với các giải pháp đề xuất thêm trong phương pháp InitTest:

using (var context = new TestContext()) 
{ 
    var objectContext = (context as IObjectContextAdapter).ObjectContext; 
    objectContext.ExecuteStoreCommand(string.Format("ALTER DATABASE [{0}] SET READ_COMMITTED_SNAPSHOT ON", context.GetType().FullName)); 
} 

kiểm tra Đơn vị:

using System.Data.Entity; 
using System.Linq; 
using System.Threading.Tasks; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace Atlit.Server.Tests.Integration.SessionProcessing 
{ 
    class TestContext : DbContext 
    { 
     public DbSet<TestEntity> TestEntities { get; set; } 
     public DbSet<ReferencingEntity> ReferencingEntities { get; set; } 
    } 

    class TestEntity 
    { 
     public int TestEntityId { get; set; } 
    } 

    class ReferencingEntity 
    { 
     public int ReferencingEntityId { get; set; } 
     public TestEntity TestEntity { get; set; } 
    } 

    [TestClass] 
    public class SaveChangesAtomicTest 
    { 
     private volatile int m_Count = 3000; 
     private volatile bool m_Failed = false; 

     [TestInitialize] 
     public void InitTest() 
     { 
      using (var context = new TestContext()) 
      { 
       var dbInitializer = new DropCreateDatabaseAlways<TestContext>(); 
       dbInitializer.InitializeDatabase(context); 
      } 
     } 

     private void AddEntities() 
     { 
      while (m_Count-- > 0 && !m_Failed) 
      { 
       var transactionOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }; 
       using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, transactionOptions)) 
       { 
        using (var context = new TestContext()) 
        { 
         var entity = context.TestEntities.Add(new TestEntity()); 
         context.ReferencingEntities.Add(new ReferencingEntity { TestEntity = entity }); 
         context.SaveChanges(); 
        } 
        transactionScope.Complete(); 
       } 
      }   
     } 

     private void ValidateEntities() 
     { 
      while (m_Count > 0 && !m_Failed) 
      { 
       if (FreeEntitiesExist()) 
       { 
        m_Failed = true; 
       } 
      }    
     } 

     [TestMethod] 
     public void TestIsSaveChangesAtomic() 
     { 
      var addTask = Task.Factory.StartNew(AddEntities); 
      var readTask = Task.Factory.StartNew(ValidateEntities); 

      addTask.Wait(); 
      readTask.Wait(); 

      Assert.IsFalse(FreeEntitiesExist(), "sanity failed"); 
      Assert.IsFalse(m_Failed, "test failed"); 
     } 

     private static bool FreeEntitiesExist() 
     { 
      using (var context = new TestContext()) 
      { 
       return (from entity in context.TestEntities 
         where !context.ReferencingEntities.Any(re => re.TestEntity.TestEntityId == entity.TestEntityId) 
         select entity) 
         .ToArray().Any(); 
      } 
     } 
    } 
} 
+0

Đây có thể là "đọc bẩn", tùy thuộc vào cơ sở dữ liệu bạn đang sử dụng và mức độ cách ly. Ví dụ, SQL Server có một mức cô lập 'READ UNCOMMITTED' (http://msdn.microsoft.com/en-us/library/ms173763(v=sql.100).aspx) cho phép một luồng đọc dữ liệu được chèn bởi một luồng khác trong một giao dịch trước khi giao dịch được thực hiện. Dữ liệu "bẩn" theo nghĩa là chúng có thể "biến mất" khỏi cơ sở dữ liệu khi luồng thứ hai quyết định quay trở lại giao dịch. Nhưng 'READ UNCOMMITTED' không phải là mặc định trong SQL Server. – Slauma

+0

@Slauma Nếu anh ấy đang sử dụng SQL Server với kết nối tổng hợp, anh ấy có thể có thể nhận được kết nối [thừa hưởng mức cô lập được đặt trước đó] (http://support.microsoft.com/kb/972915). @OhadMeir Bạn có thể thử gói các hoạt động của mình trong một 'TransactionScope' với một mức cô lập được đặt rõ ràng là' IsolationLevel.ReadCommitted' và xem lỗi có tiếp tục hay không. –

+0

đã thêm IsolationLevel.ReadCommitted - kiểm tra vẫn không thành công –

Trả lời

6

Hãy thử cơ sở dữ liệu tùy chọn "Đã đọc Ảnh chụp nhanh được cam kết" = Đúng.

Chúng tôi có cùng một loại vấn đề. Tùy chọn này đã giải quyết chúng.

Thông tin thêm về:

http://msdn.microsoft.com/en-us/library/ms173763.aspx

Add object and its relationships atomically in SQL Server database

+0

Đồng thời thêm câu trả lời để cho biết cách giải quyết nó trong bài kiểm tra đơn vị –

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