2009-03-19 39 views
15

Tôi đang ở trong một thế giới đau khổ với cái này, và tôi rất cảm kích nếu ai đó có thể giúp đỡ.ChangeConflictException trong LINQ to Sql update

Tôi có một DataContext được đính kèm vào một bảng thử nghiệm trên cơ sở dữ liệu. Bảng kiểm tra như sau:

CREATE TABLE [dbo].[LinqTests](
    [ID] [bigint] IDENTITY(1,1) NOT NULL, 
    [StringValue] [varchar](255) NOT NULL, 
    [DateTimeValue] [datetime] NOT NULL, 
    [BooleanValue] [bit] NOT NULL, 
    CONSTRAINT [PK_LinqTests] PRIMARY KEY CLUSTERED ([ID] ASC)) 
ON [PRIMARY] 

Sử dụng LINQ, tôi có thể thêm, lấy và xóa các hàng từ bảng kiểm tra, nhưng tôi không thể cập nhật liên tục - cho một UPDATE, tôi luôn luôn có được một ChangeConflictException với một sản phẩm nào Bộ sưu tập ObjectChangeConflict.MemberConflicts. Đây là mã được sử dụng:

var dataContext = new UniversityDataContext(); 
dataContext.Log = Console.Out; 

for (int i = 1; i <= 1; i++) { 
    var linqTest = dataContext.LinqTests.Where(l => (l.ID == i)).FirstOrDefault(); 

    if (null != linqTest) { 
     linqTest.StringValue += " I've been updated."; 
    } 
    else { 
     linqTest = new LinqTest { 
      BooleanValue = false, 
      DateTimeValue = DateTime.UtcNow, 
      StringValue = "I am in loop " + i + "." 
     }; 
     dataContext.LinqTests.InsertOnSubmit(linqTest); 
    } 
} 

try { 
    dataContext.SubmitChanges(ConflictMode.ContinueOnConflict); 
} 
catch (ChangeConflictException exception) { 
    Console.WriteLine("Optimistic concurrency error."); 
    Console.WriteLine(exception.Message); 
    Console.ReadLine(); 
} 

Console.ReadLine(); 

Đây là đầu ra nhật ký cho bản cập nhật được thực hiện thông qua DataContext.

UPDATE [dbo].[LinqTests] 
SET [StringValue] = @p3 
WHERE ([ID] = @p0) AND ([StringValue] = @p1) AND ([DateTimeValue] = @p2) AND (NOT ([BooleanValue] = 1)) 
-- @p0: Input BigInt (Size = 0; Prec = 0; Scale = 0) [1] 
-- @p1: Input VarChar (Size = 15; Prec = 0; Scale = 0) [I am in loop 1.] 
-- @p2: Input DateTime (Size = 0; Prec = 0; Scale = 0) [3/19/2009 7:54:26 PM] 
-- @p3: Input VarChar (Size = 34; Prec = 0; Scale = 0) [I am in loop 1. I've been updated.] 
-- Context: SqlProvider(Sql2000) Model: AttributedMetaModel Build: 3.5.30729.1 

Tôi đang chạy truy vấn này trên một cụm máy chủ SQL 2000 (8.0.2039). Tôi không thể, cho cuộc sống của tôi, tìm ra những gì đang xảy ra ở đây. Chạy một truy vấn UPDATE tương tự với DB dường như hoạt động tốt.

Cảm ơn trước vì đã được trợ giúp.

+0

xin vui lòng gửi mã bạn đang sử dụng cho các bản cập nhật – eglasius

Trả lời

28

Cuối cùng tôi đã tìm ra điều đang xảy ra với điều này. Rõ ràng, tùy chọn "không đếm" đã được bật cho máy chủ này.

Trong Microsoft SQL Server Management Studio 2005:

  1. Nhấp chuột phải vào máy chủ và nhấp Thuộc tính
  2. Mặt trái của Server Properties cửa sổ, chọn Connections trang
  3. Trong Tùy chọn kết nối mặc định, đảm bảo rằng "không đếm" không được chọn.

Dường như LINQ to SQL sử dụng @@ ROWCOUNT sau khi cập nhật phát hành séc kiểm tra đồng thời lạc quan tự động. Tất nhiên, nếu "không đếm" được bật cho toàn bộ máy chủ, @@ ROWCOUNT luôn trả về số không và LINQ to SQL sẽ ném ra một ConcurrencyException sau khi phát hành các bản cập nhật cho cơ sở dữ liệu.

Đây không phải là hành vi cập nhật duy nhất LINQ to SQL sử dụng. LINQ to SQL không thực hiện kiểm tra đồng thời lạc quan tự động với @@ ROWCOUNT nếu bạn có cột TIMESTAMP trên bảng của mình.

+6

Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. thx.ty –

+0

Bạn sẽ phải đi một lần nữa để THANK YOU THANK YOU THANK YOU! – SqlSandwiches

+2

Điều tra tốt, chỉ cần sửa một chút, LINQ to SQL có thể sử dụng giá trị 'đếm' được trả về từ máy chủ, nhưng không sử dụng @@ ROWCOUNT vì "Hàm @@ ROWCOUNT được cập nhật ngay cả khi SET NOCOUNT được BẬT". [xem tại đây] (http://msdn.microsoft.com/en-us/library/aa259204 (v = sql.80) .aspx) – Tomek

1

Có thể bất kỳ dữ liệu nào cho hàng đã thay đổi giữa thời điểm nó được truy xuất và bản cập nhật đã được thử chưa? Vì LINQ-> SQL có kiểm tra đồng thời tự động sẽ xác nhận hợp lệ nội dung của đối tượng so với các giá trị hiện đang được lưu trữ (như bạn thấy trong truy vấn được tạo). Nếu có thể là bất kỳ trường nào đã thay đổi cho hàng trong DB vs đối tượng LINQ đang theo dõi thì bản cập nhật sẽ không thành công. Nếu điều này xảy ra và vì lý do tốt và bạn biết những trường nào, bạn có thể cập nhật đối tượng trong trình thiết kế DBML; chọn trường tại nguyên nhân và thay đổi thuộc tính "Update Check" thành "Never".

+2

Tôi hiểu LINQ to chiến lược đồng thời lạc quan Sql khi cập nhật các dòng, nhưng nó hoàn toàn bất khả thi cho bất kỳ hàng nào trong bảng thử nghiệm đã được sửa đổi. Điều thú vị là, khi tôi thêm cột TIMESTAMP vào bảng, tôi không nhận được bất kỳ Xung đột Ngoại lệ nào. –

1

Tôi đã gặp sự cố tương tự với SQL Server 2008 và tùy chọn kết nối no countđã được bật.

Thay vì thay đổi Update Check tài sản để Never (như Quintin gợi ý), tôi đặt nó là WhenChanged và vấn đề đã được giải quyết.