2016-08-09 8 views
0

私のWPFアプリケーションでSQLDependencyを使用しようとしています。DependencySQL、更新時の奇妙な動作

私はデータベース

行動1(データベースからの更新)を更新する方法に応じて、2つの異なる振る舞いを持っている:最初のデータベースの変更(顧客の更新)で

  • を - >ソフトで受信クライアントリストが更新されます。
  • 2回目のデータベース変更(顧客の更新)では、ソフトは通知を受け取りますが、クエリ結果は更新されません。データベースの変更は、「顧客の作成」されている場合は
  • 私がne新規顧客

との通知を受け取る動作2(ソフトからの変更点):

  • 私は顧客から、一人の顧客を選択それをリストアップして更新します。通知を受け取り、顧客リストが更新されます。私は保存行を再更新する場合、私はまだ通知を受け取りますが、クエリの結果は更新されません。

  • しかし!私が別の顧客を更新して変更すると、私はそれを複数回行うことができます。最初の一つだけのバグ(データベースから、最初の1の後、私は通知を受け取りますが、クエリの結果をとにかく更新されません)

    コード:

    #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 
    

私がこのサンプルを使用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; } } 
} 

クエリ拡張:

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; 
    } 

} 

アップデート1: 私は次の私すべきをしませんでしたか?

CREATE QUEUE CustomerChangeMes​​sages;

CREATE SERVICE CustomerChangeNotifications ON QUEUE CustomerChangeMes​​sages ([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]);

+0

このリンクは有効ではありません –

答えて

0

ここでは2つの事柄のうちの1つが起こっているように感じます。1.イベントハンドラを早期に削除しているか、または2番目のトリガを起動していると依存トリガを無効にしています。

また、SqlDependencyが使用されているのを見たときにいつでもSqlDependencyの開始と停止を行うことができます。自分で使用したときに、アプリケーションが起動してアプリケーションで停止しました。イベントハンドラとトリガー自体の再作成は、発砲を操作するために使用されています。

私はいくつか試してみることにしました。(あなたが解決しようとしている問題がはっきりしないので、ここで少し推測しています) 1。開始点を移動してアプリの開始点と終了点に移動 2.トリガーが発生するたびに、トリガーが互いに依存しているため、すべてのトリガーを再作成することもできます。