2010-03-05 10 views
5

Chúng tôi đang cố gắng triển khai Microsoft Sync Framework vào ứng dụng của chúng tôi mà vẫn tồn tại tên miền của nó bằng cách sử dụng NHibernate.Microsoft Sync Framework xung đột với Nhibernate TooManyRowsAffectedexception

Một trong những vấn đề mà chúng tôi gặp phải là sau khi khung đồng bộ đã thay đổi cấu trúc cơ sở dữ liệu ban đầu của bạn (thêm bảng bóng và trình kích hoạt) NHibernate có vẻ khó chịu bằng cách ném một sự nhận biết toomanyrowsaffception khi bạn cố gắng chèn các đối tượng vào cơ sở dữ liệu.

Tôi tìm thấy bài viết này có giải pháp thêm SET NOCOUNT ON và OFF xung quanh mỗi câu lệnh cập nhật, nhưng vì cấu trúc bảng được tự động tạo bởi nhibernate và trình kích hoạt đồng bộ được tự động tạo bởi khung đồng bộ điều chỉnh tất cả các trình kích hoạt theo cách thủ công không thực sự là một lựa chọn.

http://www.codewrecks.com/blog/index.php/2009/03/25/nhibernate-and-toomanyrowsaffectedexception/

tôi đã cố gắng thiết lập các tài sản NOCOUNT sql server 2008 trên như mô tả trong câu hỏi này: Where's the best place to SET NOCOUNT? nhưng điều này dẫn đến một StaleStateException (-1 hàng bị ảnh hưởng, dự kiến ​​1).

Các bạn có biết liệu có cách nào để định cấu hình khung đồng bộ hóa để tự động đặt các câu lệnh NOCOUNT này trong các trình kích hoạt của nó không? Hoặc có thể là có một cách để nói với NHibernate để mong đợi nhiều hơn/ít hơn hàng đã được thay đổi? Hoặc có thể bất kỳ ai trong số các bạn có tập lệnh tự động để thêm các câu lệnh NOCOUNT này vào trình kích hoạt của khung đồng bộ hóa.

Thx trước!

Trả lời

6

Tôi nghĩ rằng cách NOCOUNT là con đường để đi. Bạn có thể làm điều này bằng cách thiết lập NOCOUNT cho tất cả các bảng được sử dụng bởi khung đồng bộ. Xem mã bên dưới. Một cách khác là để vá NHibernate và bỏ qua các updatecount xem (https://nhibernate.jira.com/browse/NH-1353).

KR,

Paul

class SqlSyncTriggerHelper 
{ 
    private const string triggerSql = @"select sys.triggers.name from sys.triggers, sys.objects 
     where sys.objects.name='{0}' and sys.objects.type = 'U' and sys.triggers.parent_id = sys.objects.object_id"; 

    private DbSyncScopeDescription syncScopeDescription; 

    public SqlSyncTriggerHelper(DbSyncScopeDescription syncScopeDescription) 
    { 
     this.syncScopeDescription = syncScopeDescription; 
    } 

    public void Apply(SqlConnection conn) 
    { 
     SqlTransaction transaction = null; 
     try 
     { 
      if (conn.State == System.Data.ConnectionState.Closed) 
      { 
       conn.Open(); 
      } 
      transaction = conn.BeginTransaction(); 
      foreach (var table in syncScopeDescription.Tables) 
      { 
       foreach (string trigger in GetTriggers(table.UnquotedLocalName, conn, transaction)) 
       { 
        AlterTrigger(trigger, conn, transaction); 
       } 
      } 
      transaction.Commit(); 
     } 
     catch 
     { 
      if (transaction != null) 
      { 
       transaction.Rollback(); 
      } 
      throw; 
     } 
     finally 
     { 
      if (transaction != null) 
      { 
       transaction.Dispose(); 
      } 
      conn.Close(); 
     } 
    } 

    private void AlterTrigger(string trigger, SqlConnection conn, SqlTransaction transaction) 
    { 
     SqlCommand newCmd = new SqlCommand(string.Format("exec sp_helptext '{0}'", trigger), conn, transaction); 
     var triggerStringBuilder = new StringBuilder(); 
     using (var reader = newCmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       triggerStringBuilder.Append(reader.GetValue(0) as string); 
      } 
     } 
     var triggerString = triggerStringBuilder.ToString(); 
     triggerString = triggerString.Replace("CREATE TRIGGER", "ALTER TRIGGER").Replace(" AS\n", " AS\nSET NOCOUNT ON\n") + "\nSET NOCOUNT OFF"; 
     var alterTriggerCommand = new SqlCommand(triggerString, conn, transaction); 
     alterTriggerCommand.ExecuteNonQuery(); 
    } 

    private IEnumerable<string> GetTriggers(string tableName, SqlConnection conn, SqlTransaction transaction) 
    { 
     var resultList = new List<string>(); 
     var command = new SqlCommand(string.Format(triggerSql, tableName), conn, transaction); 
     using (var reader = command.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       resultList.Add(reader.GetString(0)); 
      } 
     } 
     return resultList; 
    } 
}