2016-08-09 20 views
0

Ich versuche, SQLDependency in meiner WPF-Anwendung zu verwenden.DependencySQL, seltsames Verhalten bei der Aktualisierung

I 2 unterschiedliches Verhalten haben, je nachdem, wie ich die Datenbank aktualisieren

Das Verhalten 1 (Update von Datenbank):

  • Auf den ersten Datenbankänderung (Kunden Update) -> Die weiche Empfangs Benachrichtigung wird die Kundenliste aktualisiert.
  • Bei der zweiten Datenbankänderung (Kundenaktualisierung) erhält das Soft die Benachrichtigung, aber das Abfrageergebnis wird nicht aktualisiert.
  • Wenn die Datenbank ändern wird "Kunde erstellen" i erhalten die Benachrichtigung mit ne neuen Kunden

Das Verhalten 2 (Änderungen von soft):

  • wähle ich einen Kunden, vom Kunden Liste und aktualisiere es. Ich erhalte eine Benachrichtigung und die Kundenliste wird aktualisiert. Wenn ich die Sicherungszeile erneut aktualisiere, erhalte ich immer noch die Benachrichtigung, aber das Abfrageergebnis wird nicht aktualisiert.

  • Aber! Wenn ich einen anderen Kunden aktualisiere und es ändere, kann ich es mehrfach tun, die Abfrageergebnisse sind okay! nur der erste Fehler (von der Datenbank, nach dem ersten, erhalte ich die Meldung, aber Abfrageer wird nicht aktualisiert, sowieso)

    Code:.

    #region Updater 
    private IQueryable iCustomerquery = null; 
    private ImmediateNotificationRegister<Customer> notification = null; 
    RDatabase ctx = new RDatabase(); 
    
    void createCustomerRefreshQuery() 
    { 
    
        // Create the query. 
        iCustomerquery = from p in ctx.Customers select p; 
    
        notification = new ImmediateNotificationRegister<Customer>(ctx, iCustomerquery); 
        notification.OnChanged += NotificationOnChanged; 
    
    } 
    
    
    /// <summary> 
    /// When changed the data, the method will be invoked. 
    /// </summary> 
    void NotificationOnChanged(object sender, EventArgs e) 
    { 
        System.Windows.Application app = System.Windows.Application.Current; 
        app.Dispatcher.BeginInvoke(new Action(UpdateCustomer), null); 
    
    
    } 
    
    void UpdateCustomer() 
    { 
    
    
        if (CanRequestNotifications()) 
        { 
         Console.WriteLine("UPDATE"); 
    
         try 
         { 
          var customers = (iCustomerquery as DbQuery<Customer>).ToList(); 
          ClientList.Clear(); 
          foreach (var customer in customers) 
          { 
    
           ClientList.Add(customer); 
           OnPropertyChanged("ClientList"); 
    
          } 
         } 
         catch (Exception ex) 
         { 
          if (ex.InnerException != null) 
          { 
           Console.WriteLine(ex.Message + "(" + ex.InnerException.Message + ")"); 
          } 
          else 
          { 
           Console.WriteLine(ex.Message); 
          } 
         } 
        } 
        //iCustomerquery = from p in ctx.Customers select p; 
    
    } 
    
    
    private bool CanRequestNotifications() 
    { 
        // In order to use the callback feature of the 
        // SqlDependency, the application must have 
        // the SqlClientPermission permission. 
        try 
        { 
         SqlClientPermission perm = 
          new SqlClientPermission(
          PermissionState.Unrestricted); 
    
         perm.Demand(); 
    
         return true; 
        } 
        catch (SecurityException se) 
        { 
         Console.WriteLine(se.Message, "Permission Error"); 
         return false; 
        } 
        catch (Exception e) 
        { 
         Console.WriteLine(e.Message, "Error"); 
         return false; 
        } 
    } 
    /// <summary> 
    /// Stop SqlDependency. 
    /// </summary> 
    private void StopSqlDependency(object sender, EventArgs e) 
    { 
        try 
        { 
         Console.WriteLine("Stop sql dependency"); 
         if (notification != null) 
         { 
          notification.Dispose(); 
          notification = null; 
         } 
        } 
        catch (ArgumentException ex) 
        { 
         //MessageBox.Show(ex.Message, "Paramter Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 
        } 
        catch (Exception ex) 
        { 
         if (ex.InnerException != null) 
         { 
          Console.WriteLine(ex.Message + "(" + ex.InnerException.Message + ")", "Failed to Stop SqlDependency"); 
         } 
         else 
         { 
          Console.WriteLine(ex.Message, "Failed to Stop SqlDependency"); 
         } 
        } 
    } 
    
    
    #endregion 
    

Ich benutzen diese Probe aus Msdn

ImmediateNotificationRegister:

public class ImmediateNotificationRegister<TEntity> : IDisposable 
    where TEntity : class 
{ 
    private SqlConnection connection = null; 
    private SqlCommand command = null; 
    private IQueryable iquery = null; 
    private ObjectQuery oquery = null; 

    // Summary: 
    //  Occurs when a notification is received for any of the commands associated 
    //  with this ImmediateNotificationRegister object. 
    public event EventHandler OnChanged; 
    private SqlDependency dependency = null; 

    /// <summary> 
    /// Initializes a new instance of ImmediateNotificationRegister class. 
    /// </summary> 
    /// <param name="query">an instance of ObjectQuery is used to get connection string and 
    /// command string to register SqlDependency nitification. </param> 
    public ImmediateNotificationRegister(ObjectQuery query) 
    { 
     try 
     { 
      this.oquery = query; 

      QueryExtension.GetSqlCommand(oquery, ref connection, ref command); 

      BeginSqlDependency(); 
     } 
     catch (ArgumentException ex) 
     { 
      throw new ArgumentException("Paramter cannot be null", "query", ex); 
     } 
     catch (Exception ex) 
     { 
      throw new Exception(
       "Fails to initialize a new instance of ImmediateNotificationRegister class.", ex); 
     } 
    } 

    /// <summary> 
    /// Initializes a new instance of ImmediateNotificationRegister class. 
    /// </summary> 
    /// <param name="context">an instance of DbContext is used to get an ObjectQuery object</param> 
    /// <param name="query">an instance of IQueryable is used to get ObjectQuery object, and then get 
    /// connection string and command string to register SqlDependency nitification. </param> 
    public ImmediateNotificationRegister(DbContext context, IQueryable query) 
    { 
     try 
     { 
      this.iquery = query; 

      // Get the ObjectQuery directly or convert the DbQuery to ObjectQuery. 
      oquery = QueryExtension.GetObjectQuery<TEntity>(context, iquery); 

      QueryExtension.GetSqlCommand(oquery, ref connection, ref command); 

      BeginSqlDependency(); 
     } 
     catch (ArgumentException ex) 
     { 
      if (ex.ParamName == "context") 
      { 
       throw new ArgumentException("Paramter cannot be null", "context", ex); 
      } 
      else 
      { 
       throw new ArgumentException("Paramter cannot be null", "query", ex); 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new Exception(
       "Fails to initialize a new instance of ImmediateNotificationRegister class.", ex); 
     } 
    } 

    private void BeginSqlDependency() 
    { 
     // Before start the SqlDependency, stop all the SqlDependency. 
     SqlDependency.Stop(QueryExtension.GetConnectionString(oquery)); 
     SqlDependency.Start(QueryExtension.GetConnectionString(oquery)); 

     RegisterSqlDependency(); 
    } 

    private void RegisterSqlDependency() 
    { 
     if (command == null || connection == null) 
     { 
      throw new ArgumentException("command and connection cannot be null"); 
     } 

     // Make sure the command object does not already have 
     // a notification object associated with it. 
     command.Notification = null; 

     // Create and bind the SqlDependency object to the command object. 
     dependency = new SqlDependency(command); 
     dependency.OnChange += new OnChangeEventHandler(DependencyOnChange); 

     // After register SqlDependency, the SqlCommand must be executed, or we can't 
     // get the notification. 
     RegisterSqlCommand(); 
    } 

    private void DependencyOnChange(object sender, SqlNotificationEventArgs e) 
    { 
     // Move the original SqlDependency event handler. 
     SqlDependency dependency = (SqlDependency)sender; 
     dependency.OnChange -= DependencyOnChange; 

     if (OnChanged != null) 
     { 
      OnChanged(this, null); 
     } 

     // We re-register the SqlDependency. 
     RegisterSqlDependency(); 
    } 

    private void RegisterSqlCommand() 
    { 
     if (connection != null && command != null) 
     { 
      connection.Open(); 
      command.ExecuteNonQuery(); 
      connection.Close(); 
     } 
    } 

    /// <summary> 
    /// Releases all the resources by the ImmediateNotificationRegister. 
    /// </summary> 
    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected void Dispose(Boolean disposed) 
    { 
     if (disposed) 
     { 
      if (StopSqlDependency()) 
      { 
       if (command != null) 
       { 
        command.Dispose(); 
        command = null; 
       } 

       if (connection != null) 
       { 
        connection.Dispose(); 
        connection = null; 
       } 

       OnChanged = null; 
       iquery = null; 
       dependency.OnChange -= DependencyOnChange; 
       dependency = null; 
      } 
     } 
    } 

    /// <summary> 
    /// Stops the notification of SqlDependency. 
    /// </summary> 
    /// <returns>If be success, returns true;If fails, throw the exception</returns> 
    public Boolean StopSqlDependency() 
    { 
     try 
     { 
      SqlDependency.Stop(QueryExtension.GetConnectionString(oquery)); 
      return true; 
     } 
     catch (ArgumentException ex) 
     { 
      throw new ArgumentException("Parameter cannot be null.", "query", ex); 
     } 
     catch (Exception ex) 
     { 
      throw new Exception("Fails to Stop the SqlDependency in the ImmediateNotificationRegister class.", ex); 
     } 
    } 

    /// <summary> 
    /// The SqlConnection is got from the Query. 
    /// </summary> 
    public SqlConnection Connection 
    { get { return connection; } } 

    /// <summary> 
    /// The SqlCommand is got from the Query. 
    /// </summary> 
    public SqlCommand Command 
    { get { return command; } } 

    /// <summary> 
    /// The ObjectQuery is got from the Query. 
    /// </summary> 
    public ObjectQuery Oquery 
    { get { return oquery; } } 
} 

Die Abfrage Erweiterung:

public static class QueryExtension 
{ 
    /// <summary> 
    /// Return the ObjectQuery directly or convert the DbQuery to ObjectQuery. 
    /// </summary> 
    public static ObjectQuery GetObjectQuery<TEntity>(DbContext context, IQueryable query) 
     where TEntity : class 
    { 
     if (query is ObjectQuery) 
      return query as ObjectQuery; 

     if (context == null) 
      throw new ArgumentException("Paramter cannot be null", "context"); 

     // Use the DbContext to create the ObjectContext 
     ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext; 
     // Use the DbSet to create the ObjectSet and get the appropriate provider. 
     IQueryable iqueryable = objectContext.CreateObjectSet<TEntity>() as IQueryable; 
     IQueryProvider provider = iqueryable.Provider; 

     // Use the provider and expression to create the ObjectQuery. 
     return provider.CreateQuery(query.Expression) as ObjectQuery; 
    } 

    /// <summary> 
    /// Use ObjectQuery to get SqlConnection and SqlCommand. 
    /// </summary> 
    public static void GetSqlCommand(ObjectQuery query, ref SqlConnection connection, ref SqlCommand command) 
    { 
     if (query == null) 
      throw new System.ArgumentException("Paramter cannot be null", "query"); 

     if (connection == null) 
     { 
      connection = new SqlConnection(QueryExtension.GetConnectionString(query)); 
     } 

     if (command == null) 
     { 
      command = new SqlCommand(QueryExtension.GetSqlString(query), connection); 

      // Add all the paramters used in query. 
      foreach (ObjectParameter parameter in query.Parameters) 
      { 
       command.Parameters.AddWithValue(parameter.Name, parameter.Value); 
      } 
     } 
    } 

    /// <summary> 
    /// Use ObjectQuery to get the connection string. 
    /// </summary> 
    public static String GetConnectionString(ObjectQuery query) 
    { 
     if (query == null) 
     { 
      throw new ArgumentException("Paramter cannot be null", "query"); 
     } 

     EntityConnection connection = query.Context.Connection as EntityConnection; 
     return connection.StoreConnection.ConnectionString; 
    } 

    /// <summary> 
    /// Use ObjectQuery to get the Sql string. 
    /// </summary> 
    public static String GetSqlString(ObjectQuery query) 
    { 
     if (query == null) 
     { 
      throw new ArgumentException("Paramter cannot be null", "query"); 
     } 

     string s = query.ToTraceString(); 

     return s; 
    } 

} 

Update 1: I i die folgende sollte nicht getan?

CREATE QUEUE CustomerChangeMessages;

ERSTELLEN SERVICE CustomerChangeNotifications ON QUEUE CustomerChangeMessages ([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]);

+0

Dieser Link ist nicht mehr gültig –

Antwort

0

Ich fühle mich wie eine von 2 Dinge hier passiert, 1. Sie entfernen den Event-Handler vorzeitig, oder 2 feuern den primären Trigger ist ungültig den abhängigen Trigger einige, so wie es nie feuert.

Auch Ihr Problem könnte mit dem Starten und Stoppen der SqlDependency zu tun haben, wann immer ich SqlDependency verwendet habe, und wenn ich es selbst benutzt habe, wurde es beim Start der Anwendung gestartet und in der Anwendung gestoppt Ende, und die Event-Handler und die Wiederherstellung des Triggers selbst wurden verwendet, um das Feuern zu manipulieren.

Ein paar Dinge, die ich versuchen würde, (Ich rate hier etwas, weil es unklar ist, was das Problem ist, das Sie versuchen, zu lösen) 1.Verschiebe deinen Start und stoppe zum App-Start und zum Ende der App. 2. Du könntest auch alle Trigger neu erstellen, wenn sie ausgelöst werden, da sie voneinander abhängig sind.