Zusatzbefehl nach jedem Sql-Befehl des SqlCommand ausführen



  • Hallo

    Wie im Titel erwähnt, möchte ich an einen SqlBefehl noch einen Zusatzbefehl ranhängen und diesen direkt hinterher auszuführen.

    Genauer gesagt, ich hab eine Anwendung mit eine Grid. Das Grid ist direkt auf eine Tabelle in der Datenbank gebunden, so das die Änderungen direkt ohne einblicke meiner seits in die Datenbank gehen. Jetzt würde ich aber gern die Veränderungen mitprotokolieren, was aber nur geht, wenn ich auf der selben Verbindung noch einen Befehl hinterherschicke.

    Die Idee das ganz zu subclassen ist mir auch schon gekommen, aber wollte ich mir eigentlich ersparen. Daher die Frage geht es irgendwie einfacher?
    Gibt es vllt ein Event auf das man sich hängen kann und wenn ja an welcher Klasse?

    Vielen Dank im Vorraus für die Hilfe.

    MfG Marco



  • Eine Möglichkeit sind Datenbanktrigger.



  • Trigger wären eine Möglichkeit, die greifen dann allerdings global, also für alle Anwendungen, überall, automatisch, immer.
    Das kann super sein, kann aber auch sehr unerwünscht sein.

    ----

    Kann man bei diesen Data-Binding-Geschichten nicht irgendwo die SQL-Schnippsel angeben die zum Einfügen/Abholen/Ändern/Löschen von Datensätzen verwendet werden?
    Sowas da: SqlDataAdapter.InsertCommand



  • Hy

    An Trigger dachte ich auch schon ist aber auch eher der nicht gewollte Ansatz, da die Änderungen nur dann Protkoliert werden sollen, wenn sie über meine Software durchgeführt werden (UserInferface) und nicht durch die anderen Import Mechanismen.

    Und ansonst noch weitere Idee?

    Hab auch schonmal mit dem Gedanken gespielt einen eigenen Provider zu schreiben, aber ich glaub nicht das dies mir gefallen wird 😞

    MfG Marco



  • Ändert sich eine Zelle im DataGridView-Steuerelement - ich nehme an, dass du dieses verwendest - wird das CurrentCellChanged ausgelöst.

    // Ereignis anbinden
    dataGridView1.CurrentCellChanged += new System.EventHandler(dataGridView1_CurrentCellChanged);
    
    private void dataGridView1_CurrentCellChanged(object sender, EventArgs e)
    {
         // Protollierung durchführen
         ... dataGridView1.CurrentCellAdress ...
    }
    


  • Hy

    Die Idee an sich ist auch nicht schlecht, aber das Problem hier ist noch, dass bis dahin ja noch nichts gespeichert ist.

    Achja zum anderen es wird zwar C# benutzt aber das ganze in einem APS.NET MVC Projekt.

    MfG Marco



  • Was gefällt dir denn an meinem Vorschlag nicht?



  • Hy

    Der vorschlag ist gut, aber der funktioniert leider nur in WinForm, WCF und vielleicht noch in reiner ASP.NET Anwendung. Aber all dies hab ich nicht, ich benötige das ganze für ASP.NET MVC, da gibts nix mit Events, und das einzige Grid was es gibt ist von DevExpress und das erstellt auch nicht viel mehr als eine Html-Table. Also keine Events.

    Auserdem möchte ich es gern an den Stream hängen, weil ich dann so immer die Sicherheit habe, das ich nirgends die Protokollierung vergesse mit reinzupgroammieren.

    MfG Marco



  • Mein Vorschlag war einen SqlDataAdapter zu verwenden, nix mit Events.

    Das DevExpress Teil verwendet aber anscheinend eine andere Data-Adapter Klasse, nämlich DevExpress.Data.Linq.LinqServerModeDataSource.
    Und diese hat sehrwohl Events. Liest sich für mich so als ob das gehen müsste.

    Und was meinst du mit Stream?

    ----

    Nochmal dazu:

    An Trigger dachte ich auch schon ist aber auch eher der nicht gewollte Ansatz, da die Änderungen nur dann Protkoliert werden sollen, wenn sie über meine Software durchgeführt werden (UserInferface) und nicht durch die anderen Import Mechanismen.

    Wenn du keine andere Möglichkeit findest, könntest du als letzten Ausweg Trigger verwenden, die deine Applikation über den "Application Name" (kann im Connection String angegeben werden) erkennen, und nur dann protokollieren. Wäre eine garstige Lösung, aber immerhin eine mögliche Lösung 🙂

    EDIT: Hihi, ans offensichtliche denkt man zuletzt 🙂 Du könntest auch ne VIEW anlegen die "instead-of-insert", "instead-of-update" und "instead-of-delete" Trigger hat. Deine Applikation verwendet dann diese View, und andere Importer direkt die Tables. Das wäre schon wesentlich schöner, und würde auch die anderen Importer nicht unnötig bremsen.



  • Hy

    Die sache mit dem DataAdapter und den Events werd ich mir mal anschauen. Aber das je nach dem wäre das auch vllt nur die halbe Miete, denn sobald ich über eine andere Stelle, nicht dem Grid, etwas ändere funktionierts nicht mehr.

    Mit Stream meinte ich, da ich gehofft habe mich direkt in den SqlProvider an die Sql-Commandos zu hängen, oder eben einen eigenen Implementieren, welcher dies beherscht.

    Aber der Ansatz mit den Views hört sich sehr vielversprechend an. Das werd ich mir woll doch mal anschauen.

    MfG Marco

    Edit: Achja wegen deinem Link zu den DataAdapter, mann muss hier leider etwas aufpassen, ASP.NET ist nicht ASP.NET MVC (welches ich benutze).



  • Marc-O schrieb:

    Edit: Achja wegen deinem Link zu den DataAdapter, mann muss hier leider etwas aufpassen, ASP.NET ist nicht ASP.NET MVC (welches ich benutze).

    Das hattest du erst nicht dazugeschrieben.

    Und bei meinem zweiten Beitrag hab ich ja auch dazugeschrieben "Das DevExpress Teil verwendet aber anscheinend eine andere Data-Adapter Klasse", mit passendem Link dazu. 😉

    Dass du das nicht an 100 Stellen haben willst verstehe ich. Und wenn nicht alles über Grids gemacht wird, wird's noch lästiger, dann muss man sich für jede Art wie zugegriffen wird wieder ne neue Lösung suchen.

    Also ja, guck dir mal an wie das mit einer VIEW geht. Funktionieren müsste es, wenn dir die Lösung nicht zu unschön ist wäre das ne Möglichkeit.



  • jup, werd ich machen.

    Aber vielen dank nochmal.

    MfG Marco



  • Hallo

    Eins hab ich doch dazu zu sagen, es gibt die Möglichkeit einen eigenen Provider zu schreiben, an denn man sich dann hängen kann. Darauf gestossen bin ich, als ich nach einen Sql-Statment Logger fürs EntityFramework gesucht habe. Dadurch bin ich auf folgenden Artikel gestossen:

    http://blogs.msdn.com/b/jkowalski/archive/2009/06/11/tracing-and-caching-in-entity-framework-available-on-msdn-code-gallery.aspx

    In diesem wird ein Provider erstellt, mit dem man die Kommandos mitloggen kann und auch das ausgewaehlte select Cachen kann. Dies muss man entsprechend nur noch umschreiben (bzw. sich an die Events CommandExecuting, CommandFinished und/oder CommandFailed hängen) und seine eigenen Sql-Statments noch absetzten.

    Edit:
    Bzw es gibt noch was, Spezial im EntityFramework, an der Entity-Klasse kann man sich ans SavingChanges Event hängen, und dort entsprechend die veränderten Objekte wegprotokollieren. (MyDBEntities in folgenden durch eigenen Namen noch ersetzen)

    public partial class MyDBEntities
    {
      // Diese Funktion wird in allen Konstruktoren aufgerufen, so 
      // Haengen wir immer an jeder Instanz
      partial void OnContextCreated()
      {
        this.SavingChanges += delegate(object sender, EventArgs e)
        {
          // Ermittle meine Entitaet
          MyDBEntities me = (MyDBEntities)sender;
    
          foreach(var entity in me.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted))
          {
            // Debug out.....
          }
        }
      }
    }
    

    Bzw. wenn man auf der selben Connection noch ein Sql-Statment absetzten moechte (zB um die selbe SPID zu haben) kann folgender Code benutzt werden:

    public partial class MyDBEntities
    {
      // Diese Funktion wird in allen Konstruktoren aufgerufen, so 
      // Haengen wir immer an jeder Instanz
      partial void OnContextCreated()
      {
        this.SavingChanges += delegate(object sender, EventArgs e)
        {
          // Ermittle meine Entitaet
          MyDBEntities me = (MyDBEntities)sender;
    
          // Hole die Verbindung
          EntityConnection dc = (EntityConnection)me.Connection;
    
          // Dies ist wichtig, hab aber nicht rausbekommen wieso
          DbConnection storeConnection = dc.StoreConnection;
    
          // Erzeuge eigenes Commando um die userinit SP abzusetzten
          DbCommand command = storeConnection.CreateCommand();
          command.CommandText = "userinit";
          command.CommandType = CommandType.StoredProcedure;
    
          // Parameter daran noch versorgen
          command.Parameters.Add(new SqlParameter("userid", "[param]"));
    
          // Auführen des Kommandos
          command.ExecuteNonQuery();
        }
      }
    }
    

    Weitere Informationen zu der Funktion SavingChanges hier zu finden: http://msdn.microsoft.com/en-us/library/cc716714.aspx

    MfG Marco


Log in to reply