共用方式為


使用 WCF 通道模型從SQL Server接收輪詢型資料變更訊息

您可以設定 SQL 配接器來接收SQL Server資料表或檢視的定期資料變更訊息。 您可以指定配接器執行的輪詢語句來輪詢資料庫。 輪詢語句可以是 SELECT 語句或傳回結果集的預存程式。

如需配接器如何支援輪詢的詳細資訊,請參閱 支援使用輪詢的輸入呼叫

重要

如果您想要在單一應用程式中有多個輪詢作業,您必須在連線 URI 中指定 InboundID 連線屬性,使其成為唯一的一部分。 您指定的輸入識別碼會新增至作業命名空間,使其成為唯一的。

本主題示範輪詢的方式

在本主題中,若要示範 SQL 配接器如何支援接收資料變更訊息,請建立 輪詢 作業的 .NET 應用程式。 針對本主題,將 PolledDataAvailableStatement 指定為:

SELECT COUNT(*) FROM Employee  

PolledDataAvailableStatement必須傳回結果集,其中包含正值的第一個儲存格。 如果第一個儲存格不包含正值,配接器就不會執行輪詢語句。

在輪詢語句中,執行下列作業:

  1. 從 Employee 資料表中選取所有資料列。

  2. 執行預存程式 (MOVE_EMP_DATA) 將所有記錄從 Employee 資料表移至 EmployeeHistory 資料表。

  3. 執行預存程式 (ADD_EMP_DETAILS) ,將新記錄新增至 Employee 資料表。 此程式會採用員工名稱、指定和薪資作為參數。

    若要執行這些作業,您必須為 PollingStatement 系結屬性指定下列專案:

SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000   

執行輪詢語句之後,會選取 Employee 資料表中的所有記錄,並收到來自SQL Server的訊息。 配接器執行MOVE_EMP_DATA預存程式之後,所有記錄都會移至 EmployeeHistory 資料表。 然後,會執行ADD_EMP_DETAILS預存程式,將新記錄新增至 Employee 資料表。 下一個輪詢執行只會傳回單一記錄。 此迴圈會繼續執行,直到您關閉通道接聽程式為止。

使用 SQL 配接器系結屬性設定輪詢查詢

下表摘要說明您用來設定配接器以接收資料變更訊息的 SQL 配接器系結屬性。 您必須將這些系結屬性指定為 .NET 應用程式的一部分以進行輪詢。

Binding 屬性 Description
InboundOperationType 指定您要執行 PollingTypedPollingNotification 輸入作業。 預設值為 Polling
PolledDataAvailableStatement 指定配接器執行的 SQL 語句,以判斷是否有任何資料可供輪詢。 SQL 語句必須傳回包含資料列和資料行的結果集。 只有在資料列可用時,才會執行 針對 PollingStatement 系結屬性指定的 SQL 語句。
PollingIntervalInSeconds 指定間隔,以秒為單位,SQL 配接器會執行 針對 PolledDataAvailableStatement 系結屬性指定的語句。 預設值為 30 秒。 輪詢間隔會決定連續輪詢之間的時間間隔。 如果語句是在指定的間隔內執行,配接器會等候間隔中的剩餘時間。
PollingStatement 指定要輪詢SQL Server資料庫資料表的 SQL 語句。 您可以指定輪詢語句的簡單 SELECT 語句或預存程式。 預設值是 null。 您必須指定 PollingStatement 的值,才能啟用輪詢。 只有在有資料可供輪詢時,才會執行輪詢語句,這是由 PolledDataAvailableStatement 系結屬性所決定。 您可以指定以分號分隔的任意數目 SQL 語句。
PollWhileDataFound 指定 SQL 配接器是否忽略輪詢間隔,並持續執行 針對 PolledDataAvailableStatement 系結屬性指定的 SQL 語句,如果正在輪詢的資料表中有資料可用。 如果資料表中沒有可用的資料,配接器會還原為在指定的輪詢間隔執行 SQL 語句。 預設值為 false

如需這些屬性的更完整描述,請參閱閱讀 BizTalk Adapter for SQL Server 配接器系結屬性。 如需如何使用 SQL 配接器輪詢SQL Server的完整描述,請閱讀本主題的其餘部分。

使用輪詢要求訊息

配接器會叫用程式碼上的輪詢作業,以輪詢SQL Server資料庫。 也就是說,配接器會傳送您透過 IInputChannel 通道圖形收到的輪詢要求訊息。 Polling 要求訊息包含 PollingStatement 系結屬性所指定的查詢結果集。 您可以使用下列兩種方式之一來取用輪詢訊息:

  • 若要使用節點值串流來取用訊息,您必須在回應訊息上呼叫 WriteBodyContents 方法,並將實作節點值串流的 XmlDictionaryWriter 傳遞給它。

  • 若要使用節點串流來取用訊息,您可以在回應訊息上呼叫 GetReaderAtBodyContents 以取得 XmlReader

關於本主題中使用的範例

本主題中的範例會輪詢 Employee 資料表。 此範例也會使用 MOVE_EMP_DATA 和 ADD_EMP_DETAILS 預存程式。 產生這些成品的腳本會隨附範例。 如需範例的詳細資訊,請參閱 SQL 配接器的範例。 SQL 配接器範例也會提供以本主題為基礎的範例 Polling_ChannelModel

使用 WCF 通道模型接收輪詢作業的輸入訊息

本節提供有關如何撰寫 .NET 應用程式 (通道模型) ,以使用 SQL 配接器接收輸入輪詢訊息的指示。

從 SQL 配接器接收輪詢訊息

  1. 在 Visual Studio 中建立 Microsoft Visual C# 專案。 針對本主題,建立主控台應用程式。

  2. 在方案總管中,新增 、 Microsoft.ServiceModel.ChannelsSystem.ServiceModel 和 的 System.Runtime.Serialization 參考 Microsoft.Adapters.Sql

  3. 開啟 Program.cs 檔案,並新增下列命名空間:

    • Microsoft.Adapters.Sql

    • System.ServiceModel

    • System.ServiceModel.Description

    • System.ServiceModel.Channels

    • System.Xml

  4. 指定連線 URI。 如需配接器連線 URI 的詳細資訊,請參閱建立SQL Server連線 URI

    Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");  
    
  5. 建立 SqlAdapterBinding 的實例,並設定設定輪詢所需的系結屬性。 您至少必須設定 InboundOperationTypePolledDataAvailableStatementPollingStatement 系結屬性。 如需用來設定輪詢之系結屬性的詳細資訊,請參閱 支援使用輪詢的輸入呼叫

    SqlAdapterBinding binding = new SqlAdapterBinding();  
    binding.InboundOperationType = InboundOperation.Polling;  
    binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE";  
    binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";  
    
  6. 建立系結參數集合並設定認證。

    ClientCredentials credentials = new ClientCredentials();  
    credentials.UserName.UserName = "<Enter user name here>";  
    credentials.UserName.Password = "<Enter password here>";  
    
    BindingParameterCollection bindingParams = new BindingParameterCollection();  
    bindingParams.Add(credentials);  
    
  7. 建立通道接聽程式並加以開啟。 您可以在SqlAdapterBinding上叫用BuildChannelListener < IInputChannel >方法來建立接聽程式。

    IChannelListener<IInputChannel> listener = binding.BuildChannelListener<IInputChannel>(connectionUri, bindingParams);  
    listener.Open();  
    
  8. 叫用接聽程式上的AcceptChannel方法並開啟它,以取得IInputChannel通道。

    IInputChannel channel = listener.AcceptChannel();  
    channel.Open();  
    
  9. 在通道上叫用 Receive ,以從配接器取得下一個 POLLINGSTMT 訊息。

    Message message = channel.Receive();  
    
  10. 使用 POLLINGSTMT 作業所傳回的結果集。 您可以使用 XmlReaderXmlDictionaryWriter來取用訊息。

    XmlReader reader = message.GetReaderAtBodyContents();  
    
  11. 當您完成處理要求時,請關閉通道。

    channel.Close()  
    

    重要

    完成 POLLINGSTMT 作業之後,您必須關閉通道。 無法關閉通道可能會影響程式碼的行為。

  12. 當您完成接收資料變更的訊息時,請關閉接聽程式。

    listener.Close()  
    

    重要

    關閉接聽程式並不會關閉使用接聽程式建立的通道。 您必須明確關閉使用接聽程式建立的每個通道。

範例

下列範例顯示執行 Employee 資料表的輪詢查詢。 輪詢語句會執行下列工作:

  • 從 Employee 資料表中選取所有記錄。

  • 執行MOVE_EMP_DATA預存程式,將所有記錄從 Employee 資料表移至 EmployeeHistory 資料表。

  • 執行ADD_EMP_DETAILS預存程式,將單一記錄新增至 Employee 資料表。

    輪詢訊息會儲存在 C:\PollingOutput.xml

using System;  
using Microsoft.Adapters.Sql;  
using System.ServiceModel;  
using System.ServiceModel.Description;  
using System.ServiceModel.Channels;  

using System.Xml;  

namespace ConsoleApplication1  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            Console.WriteLine("Sample started. This sample will poll 5 times and will perform the following tasks:");  
            Console.WriteLine("Press any key to start polling...");  
            Console.ReadLine();  
            IChannelListener<IInputChannel> listener = null;  

            IInputChannel channel = null;  

            try  
            {  
                TimeSpan messageTimeout = new TimeSpan(0, 0, 30);  

                SqlAdapterBinding binding = new SqlAdapterBinding();  
                binding.InboundOperationType = InboundOperation.Polling;  
                binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE";  
                binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";  

                Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");  

                ClientCredentials credentials = new ClientCredentials();  
                credentials.UserName.UserName = "<Enter user name here>";  
                credentials.UserName.Password = "<Enter password here>";  

                BindingParameterCollection bindingParams = new BindingParameterCollection();  
                bindingParams.Add(credentials);  

                listener = binding.BuildChannelListener<IInputChannel>(ConnectionUri, bindingParams);  
                listener.Open();  

                channel = listener.AcceptChannel();  
                channel.Open();  

                Console.WriteLine("Channel and Listener opened...");  
                Console.WriteLine("\nWaiting for polled data...");  
                Console.WriteLine("Receive request timeout is {0}", messageTimeout);  

                // Poll five times with the specified message timeout   
                // If a timeout occurs polling will be aborted  
                for (int i = 0; i < 5; i++)  
                {  
                    Console.WriteLine("Polling: " + i);  
                    Message message = null;  
                    XmlReader reader = null;  
                    try  
                    {  
                        //Message is received so process the results  
                        message = channel.Receive(messageTimeout);  
                    }  
                    catch (System.TimeoutException toEx)  
                    {  
                        Console.WriteLine("\nNo data for request number {0}: {1}", i + 1, toEx.Message);  
                        continue;  
                    }  

                    // Get the query results using an XML reader  
                    try  
                    {  
                        reader = message.GetReaderAtBodyContents();  
                    }  
                    catch (Exception ex)  
                    {  
                        Console.WriteLine("Exception :" + ex);  
                        throw;  
                    }  

                    XmlDocument doc = new XmlDocument();  
                    doc.Load(reader);  
                    using (XmlWriter writer = XmlWriter.Create("C:\\PollingOutput.xml"))  
                    {  
                        doc.WriteTo(writer);  
                        Console.WriteLine("The polling response is saved at 'C:\\PollingOutput.xml'");  
                    }  

                    // return the cursor  
                    Console.WriteLine();  

                    // close the reader  
                    reader.Close();  

                    message.Close();  
                }  
                Console.WriteLine("\nPolling done -- hit <RETURN> to finish");  
                Console.ReadLine();  
            }  
            catch (Exception ex)  
            {  
                Console.WriteLine("Exception is: " + ex.Message);  
                if (ex.InnerException != null)  
                {  
                    Console.WriteLine("Inner Exception is: " + ex.InnerException.Message);  
                }  
            }  
            finally  
            {  
                // IMPORTANT: close the channel and listener to stop polling  
                if (channel != null)  
                {  
                    if (channel.State == CommunicationState.Opened)  
                        channel.Close();  
                    else  
                        channel.Abort();  
                }  

                if (listener != null)  
                {  
                    if (listener.State == CommunicationState.Opened)  
                        listener.Close();  
                    else  
                        listener.Abort();  
                }  
            }  
        }  
    }  
}  

另請參閱

使用 WCF 通道模型開發 SQL 應用程式