5

データベースに 2 つのテーブルがあり、1 つは例外を記録し、もう 1 つはログ メッセージを記録します。

SqlDependencyWeb ダッシュボードを更新できるように、これらのテーブルが変更されたときに通知されるオブジェクトを利用しています。私はこれを機能させました:

public IEnumerable<ElmahException> GetExceptions()
    {
        using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["elmah-sqlserver"].ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = new SqlCommand(@"SELECT [ErrorId],[Application],[Host],[Type],[Source],[Message],[User],[StatusCode],[TimeUtc],[Sequence],[AllXml]
           FROM [dbo].[ELMAH_Error] ORDER BY [TimeUtc] desc", connection))
            {
                // Make sure the command object does not already have
                // a notification object associated with it.
                command.Notification = null;

                SqlDependency dependency = new SqlDependency(command);
                dependency.OnChange += new OnChangeEventHandler(ELMAHdependency_OnChange);

                if (connection.State == ConnectionState.Closed)
                    connection.Open();

                using (var reader = command.ExecuteReader())
                    return reader.Cast<IDataRecord>()
                        .Select(x => new ElmahException()
                        {
                            ErrorId = x.GetGuid(0),
                            Application = x.GetString(1),
                            Host = x.GetString(2),
                            Type = x.GetString(3),
                            Source = x.GetString(4),
                            Error = x.GetString(5),
                            User = x.GetString(6),
                            Code = x.GetInt32(7),
                            TimeStamp = x.GetDateTime(8).ToString().Replace("T", " ")
                        }).ToList();
            }

        }
    }

    private void ELMAHdependency_OnChange(object sender, SqlNotificationEventArgs e)
    {
        Console.Write("Exception table changed!");
    }

これはうまく機能しているので、帆に風が吹いているので、ログメッセージに対して同様のことをしてみました。

 public IEnumerable<LogMessage> GetLogMessages()
    {
        using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["elmah-sqlserver"].ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = new SqlCommand(@"SELECT [application],[time_stamp],[logLevel],[logger],[message]
           FROM [dbo].[LogTable] ORDER BY [time_stamp] desc", connection))
            {
                // Make sure the command object does not already have
                // a notification object associated with it.
                command.Notification = null;

                SqlDependency dependency = new SqlDependency(command);
                dependency.OnChange += new OnChangeEventHandler(NLOGdependency_OnChange);

                if (connection.State == ConnectionState.Closed)
                    connection.Open();

                using (var reader = command.ExecuteReader())
                    return reader.Cast<IDataRecord>()
                        .Select(x => new LogMessage()
                        {
                            Application = x.GetString(0),
                            TimeStamp = x.GetDateTime(1).ToString().Replace("T", " "),
                            LogLevel = x.GetString(2),
                            Logger = x.GetString(3),
                            Message = x.GetString(4)
                        }).ToList();
            }

        }
    }

    private void NLOGdependency_OnChange(object sender, SqlNotificationEventArgs e)
    {
        Console.Write("Log table has changed!");
    }

この時点で、ログ テーブルが変更された場合にのみアラートが表示されます。これを追加SqlDependencyすると、ELMAHdependency_OnChange呼び出されることはありません。GetLogMessages()メソッドをコメントアウトすると、ELMAHdependency_OnChangeがもう一度呼び出されます。

複数のSqlDependencyオブジェクトが相互に排他的であるようです。2 つのテーブルを同時に監視する方法についてのアイデアはありますか?

4

2 に答える 2

7

セミコロンを使用して別の SqlStatement を連結することができます。

ここに私の変更を加えたコードのスニペットがあります。

 [...]
 connection.Open();

 var queries = new [] {@"SELECT [application],[time_stamp],[logLevel],[logger],[message] FROM [dbo].[LogTable] ORDER BY [time_stamp] desc",
                       @"SELECT [ErrorId],[Application],[Host],[Type],[Source],[Message],[User],[StatusCode],[TimeUtc],[Sequence],[AllXml] FROM [dbo].[ELMAH_Error] ORDER BY [TimeUtc] desc"};

 using (SqlCommand command = new SqlCommand(string.Join("; ", queries), connection))
 {
 [...]

SqlDependencyイベントを呼び出したら、再登録することも重要です。そうしないと、イベントは一度だけトリガーされます..

    private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
    {
        SqlDependency dependency = sender as SqlDependency;
        if (dependency != null) dependency.OnChange -= dependency_OnChange;

        if (e.Type == SqlNotificationType.Change)
        {
            // Do things
        }
        SetupDatabaseDependency();
    }

SetupDatabaseDependency()をセットアップするためのコードが含まれますSqlDependency

于 2015-05-05T09:40:06.313 に答える
0

クエリではなく、両方のテーブルから選択するストアド プロシージャを使用します。

CREATE PROCEDURE [dbo].[SQLDependency_TestTable1_TestTable2]
    @MaxIdxTestTable1 INT = 1, @MaxIdxTestTable2 INT = 1
AS
-- Don't do this - SQLDependency doesn't like.
--SET TRANSACTION ISOLATION LEVEL READ COMMITTED

-- Don't do this either - SQLDependency doesn't like.
--SELECT MAX(ID) FROM ehmetrology.TestTable1 
--SELECT COUNT(ID) FROM ehmetrology.TestTable1

-- See here for a whole list of things SQLDependency doesn't like:
-- stackoverflow.com/questions/7588572/what-are-the-limitations-of-sqldependency/7588660#7588660

SELECT DCIdx FROM TestTable1 WHERE Idx >= @MaxIdxTestTable1 
ORDER BY DCIdx DESC;

SELECT DCIdx FROM TestTable2 WHERE Idx >= @MaxIdxTestTable2 
ORDER BY DCIdx DESC;

GO

そして、.NET側でこれを行います(VBを許してください):

    Using adapter As New SqlDataAdapter(mSQLD_Command)
        adapter.Fill(mSQLD_DataSet, SQLD_DATASET_TABLENAME)
    End Using

    ' Reload the dataset that's bound to the grid.
    If mSQLD_DataSet.Tables.Count = 2 Then
        Dim iTest1Index As Integer = 0
        Dim iTest2Index As Integer = 0

        If Integer.TryParse(mSQLD_DataSet.Tables(0).Rows(0).Item(0).ToString, iTest1Index) Then
            If iTest1Index<> moTest1.MaxDCIdx Then
                GetTest1Data(True)
            End If
        End If

        If Integer.TryParse(mSQLD_DataSet.Tables(1).Rows(0).Item(0).ToString, iTest2Index) Then
            If iTest2Index <> moTest2.MaxDCIdx Then
                GetTest2Data()
            End If
        End If

    End If

ストアド プロシージャを使用すると、一貫性のある select ステートメントを使用する場合のように、これらすべてのレコードが移動することはありません。2 つのテーブルのいずれかが変更されるたびに通知されるため、結果を調べて、どちらが変更されたかを把握する必要があります。

于 2014-01-08T21:33:22.477 に答える