2010-03-05 5 views
5

Wir versuchen, das Microsoft Sync Framework in unserer Anwendung zu implementieren, die ihre Domäne mit NHibernate beharrt.Microsoft Sync Framework kollidiert mit Nhibernate TooManyRowsAffectedexception

Eines der Probleme, denen wir begegneten, ist, dass NHibernate nach dem Ändern der anfänglichen Datenbankstruktur (Hinzufügen von Schattentabellen und Triggern) durch das Werfen einer toomanyrowsaffectedexception gestört wird, wenn Sie versuchen, Objekte in die Datenbank einzufügen.

Ich fand diesen Artikel, der die Lösung des Hinzufügens von SET NOCOUNT ON und OFF um jede Update-Anweisung hat, aber da die Tabellenstruktur von Nhibernate automatisch generiert wird und die Sync-Trigger automatisch von dem Sync Framework manuell erstellt werden alle Trigger manuell anpassen nicht wirklich eine Option.

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

Ich habe versucht, auf die SQL Server 2008 Eigenschaft NOCOUNT Einstellung wie in dieser Frage beschrieben: Where's the best place to SET NOCOUNT? aber dies führte zu einer StaleStateException (-1 Zeilen betroffen, erwartet 1).

Wissen Sie, ob es eine Möglichkeit gibt, das Synchronisierungsframework so zu konfigurieren, dass diese NOCOUNT-Anweisungen automatisch in ihren Triggern gesetzt werden? Oder gibt es eine Möglichkeit, NHibernate mitzuteilen, dass mehr/weniger Zeilen geändert wurden? Oder vielleicht haben Sie ein automatisiertes Skript, um diese NOCOUNT-Anweisungen den Triggern des Sync-Frameworks hinzuzufügen.

Danke im Voraus!

Antwort

6

Ich denke, die NOCOUNT Weg ist der Weg zu gehen. Sie können dies tun, indem Sie NOCOUNT für alle vom Sync-Framework verwendeten Tabellen festlegen. Siehe den folgenden Code. Eine andere Möglichkeit besteht darin, NHibernate zu patchen und den updatecount zu ignorieren, siehe (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; 
    } 
}