您可以設定 SQL 配接器來接收 SQL Server 數據表或檢視的定期資料變更訊息。 您可以指定配接器執行的輪詢指令,用於輪詢資料庫。 輪詢語句可以是 SELECT 語句或傳回結果集的預存程式。
如需了解配接器如何支援輪詢的更多資訊,請參閱 輪詢使用的輸入呼叫支援。
這很重要
如果您想要在單一應用程式中有多個輪詢作業,您必須將 InboundID 連線屬性指定為連線 URI 的一部分,使其是唯一的。 您指定的輸入識別碼會新增至作業命名空間,使其是唯一的。
本主題如何展示輪詢的運作方式
在本主題中,若要示範 SQL 配接器如何支援接收數據變更訊息,請建立 輪詢 作業的 .NET 應用程式。 針對本主題,將 PolledDataAvailableStatement 指定為:
SELECT COUNT(*) FROM Employee
PolledDataAvailableStatement 必須傳回含有正值的第一個單元格的結果集。 如果第一個單元格不包含正值,配接器就不會執行輪詢語句。
在輪詢陳述中,執行下列作業:
從 Employee 資料表中選取所有數據列。
執行預存程式 (MOVE_EMP_DATA),將所有記錄從 Employee 數據表移至 EmployeeHistory 資料表。
執行預存程式 (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 應用程式的一部分以進行輪詢。
| 綁定屬性 | 說明 |
|---|---|
| InboundOperationType | 指定您要執行 輪詢、類型化輪詢 或 通知 輸入作業。 預設為 輪詢。 |
| 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通道圖形傳送您收到的輪詢要求訊息。 輪詢要求訊息包含PollingStatement系結屬性所指定的查詢結果集。 您可以使用下列兩種方式之一來取用輪詢訊息:
若要使用節點值串流來取用訊息,您必須在回應訊息上呼叫 WriteBodyContents 方法,並將實作節點值串流的 XmlDictionaryWriter 傳遞給它。
若要使用節點串流來取用訊息,您可以在回應訊息上呼叫 GetReaderAtBodyContents 來取得 XmlReader。
關於本主題中使用的範例
本主題中的範例會查詢 Employee 資料表。 此範例也會使用 MOVE_EMP_DATA 和 ADD_EMP_DETAILS 預存程式。 產生這些成品的腳本會隨附範例。 如需範例的詳細資訊,請參閱 SQL 配接器的範例。 依據此主題的範例Polling_ChannelModel,也包含在 SQL 配接器範例中。
使用 WCF 通道模型接收輪詢操作的傳入訊息
本節提供如何撰寫 .NET 應用程式(通道模型)以使用 SQL 配接器接收輸入輪詢訊息的指示。
從 SQL 配接器接收輪詢訊息
在 Visual Studio 中建立Microsoft Visual C# 專案。 針對本主題,建立主控台應用程式。
在 [方案總管] 中,新增
Microsoft.Adapters.Sql、Microsoft.ServiceModel.Channels、System.ServiceModel和System.Runtime.Serialization的參考。開啟Program.cs檔案,並新增下列命名空間:
Microsoft.Adapters.SqlSystem.ServiceModelSystem.ServiceModel.DescriptionSystem.ServiceModel.ChannelsSystem.Xml
指定連線 URI。 如需配接器連線 URI 的詳細資訊,請參閱 建立 SQL Server 連線 URI。
Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");建立 SqlAdapterBinding 的實例,並設定設定輪詢所需的系結屬性。 您至少必須設定 InboundOperationType、 PolledDataAvailableStatement 和 PollingStatement 系結 屬性。 如需用來設定輪詢之繫結屬性的詳細資訊,請參閱 使用輪詢支持輸入呼叫。
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";建立係結參數集合並設定認證。
ClientCredentials credentials = new ClientCredentials(); credentials.UserName.UserName = "<Enter user name here>"; credentials.UserName.Password = "<Enter password here>"; BindingParameterCollection bindingParams = new BindingParameterCollection(); bindingParams.Add(credentials);建立通道接聽程式並加以開啟。 您可以在 SqlAdapterBinding 上叫用 BuildChannelListener<IInputChannel> 方法來建立接聽程式。
IChannelListener<IInputChannel> listener = binding.BuildChannelListener<IInputChannel>(connectionUri, bindingParams); listener.Open();藉由在接聽程式上叫用 AcceptChannel 方法並開啟它,以取得 IInputChannel 通道。
IInputChannel channel = listener.AcceptChannel(); channel.Open();在通道上叫用 Receive ,以從配接器取得下一個 POLLINGSTMT 訊息。
Message message = channel.Receive();取用 POLLINGSTMT 作業所傳回的結果集。 您可以使用 XmlReader 或 XmlDictionaryWriter 來取用訊息。
XmlReader reader = message.GetReaderAtBodyContents();當您完成處理要求時,請關閉通道。
channel.Close()這很重要
完成 POLLINGSTMT 作業之後,您應該關閉該通道。 無法關閉通道可能會影響程式代碼的行為。
當您完成接收資料變更的訊息時,請關閉接聽程式。
listener.Close()這很重要
關閉接聽程式不會關閉使用接聽程式建立的通道。 您必須明確地關閉使用接聽程式建立的每個通道。
範例
下列範例顯示執行 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();
}
}
}
}
}