使用 SELECT 语句和 WCF 通道模型轮询 Oracle 电子商务套件
可以通过使用 SELECT 语句连续轮询 Oracle 电子商务套件中的接口表、接口视图、表和视图,将 Oracle 电子商务适配器配置为接收定期的数据更改消息。 可以将 SELECT 语句指定为轮询语句,适配器会定期执行该语句来轮询 Oracle 电子商务套件。 还可以指定执行轮询语句后适配器执行的投票后 PL/SQL 代码块。
若要启用轮询,必须指定某些绑定属性,如本主题中所述。 有关适配器如何支持轮询的详细信息,请参阅 支持使用轮询的入站调用。
使用 Oracle E-Business Suite 适配器绑定属性配置轮询操作
下表汇总了用于配置适配器以接收数据更改消息的 Oracle 电子商务适配器绑定属性。 在运行轮询应用程序时,必须指定这些绑定属性。
Binding 属性 | 说明 |
---|---|
InboundOperationType | 指定是要执行 轮询 还是 通知 入站操作。 默认值为 轮询。 |
PolledDataAvailableStatement | 指定适配器执行的 SQL 语句,以确定是否有任何数据可用于轮询。 仅当记录可用时,才会执行为 PollingInput 绑定属性指定的 SELECT 语句。 |
PollingInterval | 指定 Oracle 电子商务适配器执行为 PolledDataAvailableStatement 绑定属性指定的语句的时间间隔(以秒为单位)。 默认为 30 秒。 轮询间隔确定连续轮询之间的时间间隔。 如果在指定的时间间隔内执行语句,适配器将在此间隔内休眠剩余时间。 |
PollingInput | 指定轮询语句。 若要使用 SELECT 语句轮询,必须为此绑定属性指定 SELECT 语句。 默认值为 NULL。 必须指定 PollingInput 绑定属性的值才能启用轮询。 仅当有可供轮询的数据(由 PolledDataAvailableStatement 绑定属性确定)时,才会执行轮询语句。 |
PollingAction | 指定轮询操作的操作。 可以使用添加适配器服务引用 Visual Studio 插件从为操作生成的服务接口确定轮询操作。 |
PostPollStatement | 指定在执行 PollingInput 绑定属性指定的语句后执行的语句块。 |
PollWhileDataFound | 指定 Oracle E-Business 适配器是否忽略轮询间隔并持续执行轮询语句(如果数据在要轮询的表中可用)。 如果表中没有可用的数据,适配器将还原为按指定的轮询间隔执行轮询语句。 默认值为 false。 |
有关这些属性的更完整说明,请参阅 阅读有关 BizTalk Adapter for Oracle E-Business Suite 绑定属性的信息。 有关如何使用 Oracle 电子商务适配器轮询 Oracle 数据库的完整说明,请阅读本主题的其余部分。
本主题如何演示轮询
在本主题中,为了演示 Oracle 电子商务适配器如何支持使用 SELECT 语句接收数据更改消息,请在 Application Object Library 应用程序中轮询 MS_SAMPLE_EMPLOYEE 接口表。 运行示例随附的 create_apps_artifacts.sql 脚本以在 Oracle 电子商务套件中创建这些对象时,会创建此表。
为了演示轮询操作,我们执行以下操作:
为 PolledDataAvailableStatement 绑定属性指定 SELECT 语句,以确定 (MS_SAMPLE_EMPLOYEE) 轮询的接口表具有任何数据的位置。 在此示例中,可以将此绑定属性设置为:
SELECT COUNT (*) FROM MS_SAMPLE_EMPLOYEE
这可确保适配器仅在MS_SAMPLE_EMPLOYEE接口表具有一些记录时执行轮询语句。
为 PollingInput 绑定属性指定 SELECT 语句。 此语句检索MS_SAMPLE_EMPLOYEE接口表中的所有行。 在此示例中,可以将此绑定属性设置为:
SELECT * FROM MS_SAMPLE_EMPLOYEE FOR UPDATE
注意
有关 SELECT 语句中使用的 FOR UPDATE 子句的信息,请参阅 从 Oracle 电子商务套件接收基于轮询的数据更改消息。
将 DELETE 语句指定为 PostPollStatement 绑定属性的一部分。 此语句将删除MS_SAMPLE_EMPLOYEE接口表中的所有数据。 在此示例中,可以将此绑定属性设置为:
DELETE FROM MS_SAMPLE_EMPLOYEE
发生这种情况后,下次执行为 PollingInput 指定的语句时,它将不会提取任何数据。
在将更多数据添加到MS_SAMPLE_EMPLOYEE接口表之前,不会收到任何轮询消息,因此必须使用新记录重新填充MS_SAMPLE_EMPLOYEE接口表。 为此,可以运行示例随附的 insert_apps_data.sql 脚本。 运行此脚本后,下一个轮询操作将提取插入到表中的新记录。
使用轮询请求消息
适配器对代码调用轮询操作,以轮询 Oracle 电子商务套件。 也就是说,适配器发送通过 IInputChannel 通道形状收到的轮询请求消息。 轮询请求消息包含 PollingInput 绑定属性指定的查询的结果集。 可以通过以下两种方式之一使用轮询消息:
若要使用节点值流式处理消息,必须对响应消息调用 WriteBodyContents 方法,并向其传递实现节点值流式传输的 XmlDictionaryWriter 。
若要使用节点流式处理消息,可以对响应消息调用 GetReaderAtBodyContents 以获取 XmlReader。
关于本主题中使用的示例
本主题中的示例轮询MS_SAMPLE_EMPLOYEE接口表。 示例提供了用于生成表的脚本。 有关示例的详细信息,请参阅 Oracle EBS 适配器的示例。 基于本主题 的示例 SelectPolling_ChannelModel 也随 Oracle 电子商务适配器示例一起提供。
使用 WCF 通道模型接收轮询操作的入站消息
本部分介绍如何编写 .NET 应用程序 (通道模型) ,以使用 Oracle 电子商务适配器接收入站轮询消息。
从适配器接收轮询消息
在 Visual Studio 中创建 Microsoft Visual C# ® 项目。 对于本主题,请创建控制台应用程序。
在解决方案资源管理器中添加对 、
Microsoft.ServiceModel.Channels
、System.ServiceModel
和 的Microsoft.Adapters.OracleEBS
System.Runtime.Serialization
引用。打开 Program.cs 文件并添加以下命名空间:
Microsoft.Adapters.OracleEBS
System.ServiceModel
System.ServiceModel.Description
System.ServiceModel.Channels
System.Xml
指定连接 URI。 有关适配器连接 URI 的详细信息,请参阅 创建 Oracle 电子商务套件连接 URI。
Uri ConnectionUri = new Uri("oracleebs://ebs_instance_name");
创建 OracleEBSBinding 实例并设置配置轮询所需的绑定属性。 至少必须设置 InboundOperationType、 PolledDataAvailableStatement、 PollingInput 和 PollingAction 绑定属性。 有关用于配置轮询的绑定属性的详细信息,请参阅 支持使用轮询的入站调用。
OracleEBSBinding binding = new OracleEBSBinding(); binding.InboundOperationType = InboundOperation.Polling; binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM MS_SAMPLE_EMPLOYEE"; binding.PollingInput = "SELECT * FROM MS_SAMPLE_EMPLOYEE FOR UPDATE"; binding.PollingAction = "InterfaceTables/Poll/FND/APPS/MS_SAMPLE_EMPLOYEE"; binding.PostPollStatement = "DELETE FROM MS_SAMPLE_EMPLOYEE";
由于轮询接口表,因此还必须设置应用程序上下文。 有关设置应用程序上下文所需的应用程序上下文和绑定属性的详细信息,请参阅 设置应用程序上下文。
binding.OracleUserName = "<Enter user name here>"; binding.OraclePassword = "<Enter password here>"; binding.OracleEBSResponsibilityName = "<Enter responsibility here>";
创建绑定参数集合并设置凭据。
ClientCredentials credentials = new ClientCredentials(); credentials.UserName.UserName = "<Enter user name here>"; credentials.UserName.Password = "<Enter password here>"; BindingParameterCollection bindingParams = new BindingParameterCollection(); bindingParams.Add(credentials);
创建并打开通道侦听器。 通过在 OracleEBSBinding 上调用 BuildChannelListener<IInputChannel> 方法来创建侦听器。
IChannelListener<IInputChannel> listener = binding.BuildChannelListener<IInputChannel>(connectionUri, bindingParams); listener.Open();
通过在侦听器上调用 AcceptChannel 方法获取 IInputChannel 通道,并将其打开。
IInputChannel channel = listener.AcceptChannel(); channel.Open();
在通道上调用 Receive ,从适配器获取下一个入站消息。
Message message = channel.Receive();
使用入站操作返回的结果集。 可以使用 XmlReader 或 XmlDictionaryWriter 来使用消息。
XmlReader reader = message.GetReaderAtBodyContents();
完成处理请求后关闭通道。
channel.Close()
重要
处理完入站操作后,必须关闭通道。 关闭通道失败可能会影响代码的行为。
接收完数据更改的消息后,关闭侦听器。
listener.Close()
重要
关闭侦听器不会关闭使用侦听器创建的通道。 必须显式关闭使用侦听器创建的每个通道。
示例
以下示例演示轮询MS_SAMPLE_EMPLOYEE接口表的轮询应用程序。 PollingInput 属性包含 select 语句,该语句从MS_SAMPLE_EMPLOYEE表读取所有数据,post 轮询语句删除同一表中的所有数据。 轮询消息将写入 C:\PollingOutput.xml
。
在将更多数据添加到MS_SAMPLE_EMPLOYEE接口表之前,后续轮询消息将不包含任何记录。 为此,可以运行示例随附的 insert_apps_data.sql 脚本。 运行此脚本后,下一个轮询操作将提取插入到表中的新记录。 适配器将继续轮询,直到你通过按 <RETURN> 关闭服务主机。
using System;
using Microsoft.Adapters.OracleEBS;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.Xml;
namespace SelectPolling_ChannelModel
{
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);
OracleEBSBinding binding = new OracleEBSBinding();
binding.InboundOperationType = InboundOperation.Polling;
binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM MS_SAMPLE_EMPLOYEE";
binding.PollingInput = "SELECT * FROM MS_SAMPLE_EMPLOYEE FOR UPDATE";
binding.PollingAction = "InterfaceTables/Poll/FND/APPS/MS_SAMPLE_EMPLOYEE";
binding.PostPollStatement = "DELETE FROM MS_SAMPLE_EMPLOYEE";
binding.OracleUserName = "<Enter user name here>";
binding.OraclePassword = "<Enter password here>";
binding.OracleEBSResponsibilityName = "<Enter responsibility here>";
Uri ConnectionUri = new Uri("oracleebs://ebs_instance_name?");
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);
Console.ReadLine();
if (ex.InnerException != null)
{
Console.WriteLine("Inner Exception is: " + ex.InnerException.Message);
Console.ReadLine();
}
}
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();
}
}
}
}
}