2017-01-01 14 views
0

SqlDependencyを使用してデータベースを監視するコンソールアプリケーションがあります。このアプリは、データベーステーブルを監視し、新しいレコードがテーブルに追加されると電子メールを送信することです。SQL依存関係はテーブル全体を照会します

すべて正常に動作します。新しいレコードが追加されるたびに、クエリ全体が再度実行され、テーブル内のすべてのレコードが返されます。私が実際に望むのは、テーブルに新しく追加されたレコードだけを返すことです。ここで

は、以下の私のコードです:

SQLWatcherクラス:

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Data.SqlClient; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace TestApp 
{ 
    public enum SqlWatcherNotificationType 
    { 
     Blocking, 
     Threaded // Launch in another thread so SqlWatcher can immediately start monitoring again. 
    } 

    public class SqlWatcher : IDisposable 
    { 
     private string ConnectionString; 
     private SqlConnection Connection; 
     private SqlCommand Command; 
     private SqlDataAdapter Adapter; 
     private DataSet Result; 
     private SqlWatcherNotificationType NotificationType; 

     public SqlWatcher(string ConnectionString, SqlCommand Command, SqlWatcherNotificationType NotificationType) 
     { 
      this.NotificationType = NotificationType; 
      this.ConnectionString = ConnectionString; 

      SqlDependency.Start(this.ConnectionString); 

      this.Connection = new SqlConnection(this.ConnectionString); 
      this.Connection.Open(); 
      this.Command = Command; 
      this.Command.Connection = this.Connection; 

      Adapter = new SqlDataAdapter(this.Command); 
     } 

     public void Start() 
     { 
      RegisterForChanges(); 
     } 

     public void Stop() 
     { 
      SqlDependency.Stop(this.ConnectionString); 
     } 

     public delegate void SqlWatcherEventHandler(DataSet Result); 

     public event SqlWatcherEventHandler OnChange; 

     public DataSet DataSet 
     { 
      get { return Result; } 
     } 

     private void RegisterForChanges() 
     { 
      // Remove old dependency object 
      this.Command.Notification = null; 

      // Create new dependency object 
      SqlDependency dep = new SqlDependency(this.Command); 
      dep.OnChange += new OnChangeEventHandler(Handle_OnChange); 

      // Save data 
      Result = new DataSet(); 
      Adapter.Fill(Result); 

      // Notify client of change to DataSet 
      switch (NotificationType) 
      { 
       case SqlWatcherNotificationType.Blocking: 
        OnChange(Result); 
        break; 

       case SqlWatcherNotificationType.Threaded: 
        ThreadPool.QueueUserWorkItem(ChangeEventWrapper, Result); 
        break; 
      } 
     } 

     public void ChangeEventWrapper(object state) 
     { 
      DataSet Result = (DataSet)state; 
      OnChange(Result); 
     } 

     private void Handle_OnChange(object sender, SqlNotificationEventArgs e) 
     { 
      if (e.Type != SqlNotificationType.Change) 
       throw new ApplicationException("Failed to create queue notification subscription!"); 

      //Clean up the old notification 
      SqlDependency dep = (SqlDependency)sender; 
      dep.OnChange -= Handle_OnChange; 

      //Register for the new notification 
      RegisterForChanges(); 
     } 

     public void Dispose() 
     { 
      Stop(); 
     } 
    } 
} 

実装:

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Data.Linq; 
using System.Data.SqlClient; 
using System.Linq; 
using System.Net.Mail; 
using System.Text; 
using System.Threading.Tasks; 

namespace TestApp 
{ 
    class Program 
    { 
     private static SqlWatcher SqlQueueWatcher; 

     // string pin = string.Empty; 
     string siteURL = "http://docapp/sites/nlpc"; 

     public string benefitCheck() 
     { 
      DataContext db = new DataContext("Data Source=;Initial Catalog=ServiceTest;User ID=;password = ;Integrated Security=true"); 
      BenefitDocModel RSAName = new BenefitDocModel(); 
      CustomerCareContextDataContext LandingDb = new CustomerCareContextDataContext(siteURL); 
      IEnumerable<BenefitDocModel> r = db.GetTable<BenefitDocModel>().ToList<BenefitDocModel>(); 

      var query = r.ToList(); 

      var rsa = from rr in query 
         select (new { rr.PIN , rr.Document_Name, rr.Firstname, rr.Surname, rr.URL}); 

      foreach (var rsapin in rsa) 
      { 
       Console.WriteLine(rsapin); 
       // sendEmail(rsapin.PIN); 
      } 
       /*pin = RSAName.PIN; 
       RSAsLibraryDocument test = new RSAsLibraryDocument(); 
       BenefitDocModel RSAName1 = db.GetTable<BenefitDocModel>().FirstOrDefault(x => x.PIN == pin); 
      if (pin == RSAName1.PIN) 
       { 
        test.PIN = RSAName.PIN; 
        test.UserID = RSAName.UserID; 
        test.Firstname = RSAName.Firstname; 
        test.Surname = RSAName.Surname; 
        test.Document_Name = RSAName.Document_Name; 
        test.Document_URL = RSAName.URL; 
        test.UserType = RSAName.UserType; 
        test.Name = RSAName.PIN + RSAName.Document_Name; 
       }*/ 
      return "success"; 

      }// 

     public void SQLServiceStartForLog() 
     { 
      //BenefitDocModel rsapin = db.GetTable<BenefitDocModel>().FirstOrDefault(x => x.PIN == pin); 
      //cmd.Notification = null; 
      string connS = "Data Source=;Initial Catalog=ServiceTest;User ID=;password = ;Integrated Security=true"; 
      SqlCommand cmd = new SqlCommand(); 
      //cmd.Notification = null; 
      cmd = new SqlCommand("SELECT UserID, Surname, Firstname, PIN, URL, Document_Name FROM dbo.BenefitDoc"); 
      cmd.CommandType = CommandType.Text; 
      SqlQueueWatcher = new SqlWatcher(connS, cmd, SqlWatcherNotificationType.Blocking); 
      SqlQueueWatcher.OnChange += new SqlWatcher.SqlWatcherEventHandler(QueueSQLWatcher_OnChangeForLog); 
      cmd.Notification = null; 
      SqlQueueWatcher.Start(); 
     } 
     private void QueueSQLWatcher_OnChangeForLog(DataSet Result) 
     { 
      try 
      { 
       Console.WriteLine("Database monitoring is starting...."); 
       benefitCheck(); 
       Console.WriteLine("Database monitoring completed."); 

      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.ToString()); 
      } 
     } 
     public void sendEmail(string pin) 
     { 
      MailMessage mail = new MailMessage("", ""); 
      SmtpClient client = new SmtpClient(); 
      client.Port = 25; 
      client.DeliveryMethod = SmtpDeliveryMethod.Network; 
      client.UseDefaultCredentials = false; 
      client.Host = "smtp.gmail.com"; 
      client.EnableSsl = true; 
      client.Credentials = new System.Net.NetworkCredential("", ""); 
      mail.Subject = "New Record added for RSA with " + pin; 
      mail.Body = "The benefit application for user has been created."; 
      client.Send(mail); 
     } 

     public static void Stop() 
     { 
      SqlQueueWatcher.Dispose(); 
     } 
     static void Main(string[] args) 
     { 
      Program n = new Program(); 
      n.SQLServiceStartForLog(); 
      Console.ReadLine(); 
     } 
    } 
} 
+0

これは「デモ」のユースケースですか、テーブルが変更されたときに電子メールを送信する必要がありますか?後であれば、この記事を読んでください:http://dba.stackexchange.com/questions/15613/elegant-way-of-sending-e-mails-with-service-broker –

+0

ありがとうございましたLuc、よくメールを送ります問題ではありません。問題は、新しく追加されたレコードだけを返し、現時点ではすべてのレコードを返さないようにすることです。 –

+0

私の主なポイントは、あなたが達成しようとしていることを達成するためにSQLサーバに既に「ビルトイン」機能があることです。なぜホイールを再発明するのですか?私もこれを見つけました:http://stackoverflow.com/a/10755518/172769 –

答えて

0

方法SqlDependency作品ではありません。基本的には、クエリを実行し、クエリ結果が変更された場合は通知をトリガします。しかし、データエリアを実行すると、変更が返されるだけではありません。それは、通常のクエリであるかのようにデータを返します。

変更を取得する場合は、テーブル内にLastModifiedDateTimeのような列を設定し、前回レコードを取得したときよりもLastModifiedDateTimeが大きいレコードをクエリする必要があります。

また、使用したい場合は、this NuGetパッケージがあります。

+0

ありがとう、これは私のために働いた。 –

関連する問題