<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>All Free Tech &#187; Oracle</title>
	<atom:link href="http://www.allfreetech.com/category/database/oracle-database/feed" rel="self" type="application/rss+xml" />
	<link>http://www.allfreetech.com</link>
	<description>For developers</description>
	<lastBuildDate>Tue, 01 Feb 2011 13:45:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Caching Oracle Data for ASP.NET Applications</title>
		<link>http://www.allfreetech.com/microsoft-net/asp-net/caching-oracle-data-for-asp-net-applications-144.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/asp-net/caching-oracle-data-for-asp-net-applications-144.html#comments</comments>
		<pubDate>Fri, 29 Jan 2010 13:46:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[oracle]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=144</guid>
		<description><![CDATA[&#160; For building scalable and high-performance Web based applications, ASP.NET provides a feature called data caching. Data caching enables programmatic storing of frequently accessed data objects in memory. This feature can be extended to vastly improve performance for ASP.NET applications that query data stored in an Oracle database. This article describes a strategy for caching [...]]]></description>
			<content:encoded><![CDATA[<p>&nbsp;</p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">For building scalable and high-performance Web based applications, ASP.NET provides a feature called data caching. Data caching enables programmatic storing of frequently accessed data objects in memory. This feature can be extended to vastly improve performance for ASP.NET applications that query data stored in an Oracle database. This article describes a strategy for caching Oracle database data in ASP.NET Web applications deployed using a Web Farm environment. This technique enables caching of frequently accessed Oracle database data in memory rather than making frequent database calls to retrieve the data. This helps to avoid unnecessary roundtrips to the Oracle database server. Further the article proposes an implementation for maintaining the cached data so it is always in sync with the corresponding data in the Oracle database.<span id="more-144"></span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsTitle" style="font-weight: bold; font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: 12pt; ">Data Caching in ASP.NET</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">Data Caching in ASP.NET is facilitated via the Cache class and the CacheDependency class in the System.Web.Caching namespace. The Cache class provides methods for inserting data and retrieving data from the cache. The CacheDependency class enables dependencies to be specified for the data items placed in the cache. An expiration policy for an item can be specified when we add it to the cache using the Insert method or Add method. We can define the life span for an item in the cache by using the absoluteExpiration parameter in the Insert method. This parameter allows one to specify the exact datetime that the corresponding data item will expire. One can also use the slidingExpiration parameter, specifying the elapsed time before the item will expire based on the time it was accessed. Once the item expires, it is removed from the cache. Attempts to access it will return a null value unless the item is added to the Cache again.</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsTitle" style="font-weight: bold; font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: 12pt; ">Specifying Dependencies for Cache</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">ASP.NET allows us to define the dependency of a cached item based on an external file, a directory, or another cached item. These are described as file dependencies and key dependencies. If a dependency changes, the cached item gets automatically invalidated and removed from the cache. We can use this approach to delete items from the cache when the corresponding data source changes. For example, if we write an application that retrieves data from an XML file and displays it in a grid, we can store the data from the file in the Cache and specify a Cache dependency on the XML file. When the XML file is updated, the data item gets removed from the cache. When this event occurs, the application reads the XML file again, and the latest copy of the data item is inserted into the cache again. Further, callback event handlers can be specified as a listener for getting notified when the cache item gets deleted from the cache. This eliminates the need to continuously poll the cache to determine whether the data item has been invalidated.</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsTitle" style="font-weight: bold; font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: 12pt; ">ASP.NET Cache Dependency on Oracle Database</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">Let us consider a scenario where data is stored in the Oracle database and accessed by an ASP.NET application using ADO.NET. Furthermore, let us assume that the data in the database table(s) is generally static but accessed frequently by the Web application. In a nutshell, there are very few DML operations on the table but lots of Selects on the data. Such a scenario is ideal for data caching. But unfortunately, ASP.NET does not allow a dependency to be specified whereby a cache item is dependent on data stored in a database table. Furthermore, in real world Web based systems, the Web server and the Oracle database server could be potentially running on different machines, making this cache invalidation process more challenging. Also most Web-based applications are deployed using Web farms with instances of the same application running on multiple Web servers for load balancing. This scenario makes the database caching problem slightly more complex.</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">For exploring the solution to the above problem, let&#39;s put together a sample Web application to illustrate how it can be implemented. For our example, we use ASP.NET application implemented in VB .Net communicating with the Oracle 9i database using Oracle Data Provider for .NET (ODP).</span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">In this example, consider a table named Employee in the Oracle database. We define a trigger for insert, update and delete operations on the Employee table. This trigger calls a PL/SQL function that serves as a wrapper for a Java stored procedure. This Java stored procedure in turn will be responsible for updating the Cache dependency file.</span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsTitle" style="font-weight: bold; font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: 12pt; ">ASP.NET Tier Implementation Using VB.NET</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">On the ASP.NET tier, we have a listener class containing a callback method to handle the notification when the cache item gets invalidated.</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">The callback method RemovedCallback is registered by using a delegate function. The callback method onRemove declaration must have the same signature as the CacheItemRemovedCallback delegate declaration.</span></span></p>
<p>&nbsp;</p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span style="font-size: 10pt; font-family: 'Courier New'; "><span>&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style="color: blue; ">Dim</span><span>&nbsp;onRemove&nbsp;<span style="color: blue; ">As</span>&nbsp;CacheItemRemovedCallback =&nbsp;<span style="color: blue; ">Nothing<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span style="color: blue; "><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span>onRemove =&nbsp;<span style="color: blue; ">New</span>&nbsp;CacheItemRemovedCallback(<span style="color: blue; ">AddressOf</span>&nbsp;RemovedCallback)</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">The definition for the listener event handler method RemovedCallback responsible for handling the notification from the database trigger is illustrated below. When the cache item gets invalidated, data is retrieved from the database by using the database method call getRecordFromdatabase(). The parameter &quot;key&quot; refers to the index location for the item removed from the cache. The parameter &quot;value&quot; refers to the data object removed from the cache. The parameter &quot;CacheItemRemovedReason&quot; specifies the reason causing the data item to be removed from the cache.</span></span></p>
<p>&nbsp;</p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span style="color: blue; ">Public</span><span><span style="color: blue; ">Sub</span>&nbsp;RemovedCallback(<span style="color: blue; ">ByVal</span>&nbsp;key&nbsp;<span style="color: blue; ">As</span><span style="color: blue; ">String</span>,&nbsp;<span style="color: blue; ">ByVal</span>&nbsp;value&nbsp;<span style="color: blue; ">As</span><span style="color: blue; ">Object</span>,<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>ByVal reason&nbsp;<span style="color: blue; ">As</span>&nbsp;CacheItemRemovedReason)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Dim</span>&nbsp;Source&nbsp;<span style="color: blue; ">As</span>&nbsp;DataView<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>Source = getRecordFromdatabase()<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>Cache.Insert(&quot;employeeTable &quot;, Source,&nbsp;<span style="color: blue; ">New</span><o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>System.Web.Caching.CacheDependency(&quot;d:\download\tblemployee.txt&quot;),<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>CacheItemPriority.Normal, onRemove)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span style="color: blue; ">End</span><span><span style="color: blue; ">Sub<o:p></o:p></span></span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">The method getRecordFromdatabase() is responsible for querying the database table Employee and it returns a DataView object reference. It makes use of a stored procedure called getEmployee to abstract the SQL for retrieving the data from the Employee table. The method expects a parameter called p_empid representing the primary key for the Employee table.</span></span></p>
<p>&nbsp;</p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span style="color: blue; ">Public</span><span><span style="color: blue; ">Function</span>&nbsp;getRecordFromdatabase (<span style="color: blue; ">ByVal</span>&nbsp;p_empid&nbsp;<span style="color: blue; ">As</span>&nbsp;Int32)&nbsp;<span style="color: blue; ">As</span>&nbsp;DataView<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Dim</span>&nbsp;con&nbsp;<span style="color: blue; ">As</span>&nbsp;OracleConnection =&nbsp;<span style="color: blue; ">Nothing<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&nbsp;&nbsp;</span><span style="color: blue; ">Dim</span>&nbsp;cmd&nbsp;<span style="color: blue; ">As</span>&nbsp;OracleCommand =&nbsp;<span style="color: blue; ">Nothing<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Dim</span>&nbsp;ds&nbsp;<span style="color: blue; ">As</span>&nbsp;DataSet =&nbsp;<span style="color: blue; ">Nothing<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span style="color: blue; ">&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Try<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>con = getDatabaseConnection(<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">&quot;UserId=scott;Password=tiger;Data Source=testingdb;&quot;</span>)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>cmd =&nbsp;<span style="color: blue; ">New</span>&nbsp;OracleCommand(&quot;Administrator.getEmployee&quot;, con)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>cmd.CommandType = CommandType.StoredProcedure<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>cmd.Parameters.Add(<span style="color: blue; ">New</span>&nbsp;OracleParameter(&quot;employeeId&quot;,<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>OracleDbType.Int64)).Value = p_empid<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Dim</span>&nbsp;param&nbsp;<span style="color: blue; ">As</span><span style="color: blue; ">New</span>&nbsp;OracleParameter(&quot;RC1&quot;, OracleDbType.RefCursor)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>cmd.Parameters.Add(param).Direction = ParameterDirection.Output<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Dim</span>&nbsp;myCommand&nbsp;<span style="color: blue; ">As</span><span style="color: blue; ">New</span>&nbsp;OracleDataAdapter(cmd)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>ds =&nbsp;<span style="color: blue; ">New</span>&nbsp;DataSet<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>myCommand.Fill(ds)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Dim</span>&nbsp;table&nbsp;<span style="color: blue; ">As</span>&nbsp;DataTable = ds.Tables(0)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Dim</span>&nbsp;index&nbsp;<span style="color: blue; ">As</span>&nbsp;Int32 = table.Rows.Count<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Return</span>&nbsp;ds.Tables(0).DefaultView<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Catch</span>&nbsp;ex&nbsp;<span style="color: blue; ">As</span>&nbsp;Exception<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Throw</span><span style="color: blue; ">New</span>&nbsp;Exception(&quot;Exception in Database Tier Method<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>getRecordFromdatabase () &quot; + ex.Message, ex)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Finally<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Try<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>cmd.Dispose()<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Catch</span>&nbsp;ex&nbsp;<span style="color: blue; ">As</span>&nbsp;Exception<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Finally<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>cmd =&nbsp;<span style="color: blue; ">Nothing<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">End</span><span style="color: blue; ">Try<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Try<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>con.Close()<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Catch</span>&nbsp;ex&nbsp;<span style="color: blue; ">As</span>&nbsp;Exception<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Finally<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>con =&nbsp;<span style="color: blue; ">Nothing<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">End</span><span style="color: blue; ">Try<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">End</span><span style="color: blue; ">Try<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">End</span><span style="color: blue; ">Function<o:p></o:p></span></span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">The function getDatabaseConnection accepts a connectionstring as an argument and returns an OracleConnection object reference.</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span style="color: blue; ">&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span style="color: blue; ">Public</span><span><span style="color: blue; ">Function</span>&nbsp;getDatabaseConnection(ByVal strconnection as string)&nbsp;<span style="color: blue; ">As</span><o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>OracleConnection<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Dim</span>&nbsp;con&nbsp;<span style="color: blue; ">As</span>&nbsp;Oracle.DataAccess.Client.OracleConnection =&nbsp;<span style="color: blue; ">Nothing<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Try<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>con =&nbsp;<span style="color: blue; ">New</span>&nbsp;Oracle.DataAccess.Client.OracleConnection<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>con.ConnectionString = strconnection<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>con.Open()<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Return</span>&nbsp;con<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Catch</span>&nbsp;ex&nbsp;<span style="color: blue; ">As</span>&nbsp;Exception<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">Throw</span><span style="color: blue; ">New</span>&nbsp;Exception(&quot;Exception in Database Tier Method<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>getOracleConnection() &quot; + ex.Message, ex)<o:p></o:p></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: blue; ">End</span><span style="color: blue; ">Try<o:p></o:p></span></span></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span><span>&nbsp;</span><span style="color: blue; ">End</span><span style="color: blue; ">Function<o:p></o:p></span></span></span></span></p>
<p>&nbsp;</p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsTitle" style="font-weight: bold; font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: 12pt; ">Oracle Database Tier Implementation</span></span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">The Trigger body defined for DML events on the Employee Table is shown below. This trigger simply invokes a PL/SQL wrapper function for updating an operating system file called tblemployee.txt. Copies of this file are updated on two different machines called machine1 and machine2 that are running different instances of the same Web application to enable load balancing. Here administrator refers to the owner of the schema objects in the Oracle database.</span></span></span></p>
<p>&nbsp;</p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">begin</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;</span>administrator.plfile(&#39;machine1\\download\\<span>&nbsp;tblemployee</span>.txt&#39;);</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;</span>administrator.plfile(&#39;machine2\\download\\<span>&nbsp;tblemployee</span>.txt&#39;);</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">end;</span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">For updating the cache dependency file, we will need to write a C function or a Java stored procedure. In our example, we chose a Java stored procedure since Oracle database server has a built-in JVM, making it easy to write Java stored procedures. Adequate memory must be allocated for the Java Pool in the System global area (SGA) of the Oracle instance. The static method updateFile accepts an absolute pathname as a parameter and creates the cache dependency file in the appropriate directory. If the file already exists, it is deleted and created again.</span></span></p>
<p>&nbsp;</p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">import java.io.*;</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">&nbsp;<o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">public class UpdFile {</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">&nbsp;<o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;</span>public static void updateFile(String filename) {</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">&nbsp;<o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;&nbsp;</span>try {</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;&nbsp;</span>File f = new File(filename);</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;&nbsp;</span>f.delete();</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>f.createNewFile();</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;</span>}</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;</span>catch (IOException e)</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;</span>{</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>// log exception</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;&nbsp;&nbsp;</span>}</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; "><span>&nbsp;&nbsp;</span>}</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">};</span></span></p>
<p><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">The pl/sql wrapper implementation is shown below. The wrapper function accepts the filename as a parameter and invokes the method updateFile in the Java stored procedure.</span></span></p>
<p>&nbsp;</p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">(p_filename<span>&nbsp;&nbsp;</span>IN<span>&nbsp;&nbsp;</span>VARCHAR2)</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">AS LANGUAGE JAVA</span></span></p>
<p class="MsoNormal" style="margin-top: 0in; margin-right: 0in; margin-bottom: 0.0001pt; margin-left: 0in; font-size: 12pt; font-family: 'Times New Roman'; line-height: normal; color: windowtext; "><span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: medium; "><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">NAME &#39;UpdFile.updateFile (java.lang.String)&#39;;</span></span></p>
<p><span class="clsTitle" style="font-weight: bold; font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: 12pt; ">Database Caching in a Web Farm Deployment</span></p>
<p><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">As illustrated in the example we have discussed, Web Servers machine1 and machine2 constitute the Web farm to provide load balancing for our Web application. Each machine runs an instance of the same Web application. In this scenario, each instance of the Web application can have its own copy of the cached data stored in its Cache object. When the employee table changes, the corresponding database trigger updates the file tblemployee.txt on both of these machines. Each instance of the Web application specifies a cache dependency on the local file tblemployee.txt, and the cache for both the instances in the Web Farm gets updated correctly, enabling the data cache on both the instances to remain in sync with the database table Employee.</span></p>
<p><span class="clsTitle" style="font-weight: bold; font-family: 'Arial, Helvetica,MS Sans Serif'; font-size: 12pt; ">Conclusion</span></p>
<p><span class="clsBlurb" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 10pt; ">Data Caching can be an effective technique for optimizing ASP.NET applications using the Oracle database. Although ASP.NET does not allow database dependency to be specified for the cache, Oracle triggers in conjunction with Java stored procedures can be used to extend the power of the ASP.NET cache to enable Oracle database caching. This technique can also be applied to Web Farm deployments.</span></p>
<p><strong><span class="Apple-style-span" style="font-family: 'Arial, Helvetica,  MS Sans Serif'; font-size: 13px; ">Narayan Veeramani</span></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/asp-net/caching-oracle-data-for-asp-net-applications-144.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating an Ajax Process Using PHP and Oracle</title>
		<link>http://www.allfreetech.com/php/creating-an-ajax-process-using-php-and-oracle-113.html</link>
		<comments>http://www.allfreetech.com/php/creating-an-ajax-process-using-php-and-oracle-113.html#comments</comments>
		<pubDate>Sat, 23 Jan 2010 07:30:42 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[oracle]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=113</guid>
		<description><![CDATA[For some time now, Ajax (Asynchronous JavaScript and XML), has been all the rage in the Web development world. Coming to the forefront with some of Google&#39;s features (Suggest, Maps, Gmail, and so on), Ajax performs server requests without the user having to submit a form or click on a link. In other words, the [...]]]></description>
			<content:encoded><![CDATA[<p>For some time now, Ajax (Asynchronous JavaScript and XML), has been all the rage in the Web development world. Coming to the forefront with some of Google&#39;s features (Suggest, Maps, Gmail, and so on), Ajax performs server requests without the user having to submit a form or click on a link. In other words, the Web browser can make the server request, and handle the response, without the user doing anything or even knowing that this is happening. The immediacy that Ajax brings is not only a great convenience, but it can also be downright cool.</p>
<p>In this recipe, I discuss all the code necessary to use Ajax to go from a simple Web page to a JavaScript function to an XMLHttpRequest to a PHP script and, finally, to an Oracle database. Along with the code, I do talk about the individual pieces with respect to the whole picture: what each chunk does and why it&#39;s important. By reading this HowTo, you will acquire not only some sample code but also, hopefully, a broader understanding of the whole Ajax concept.</p>
<p><span class="parahead1">Background</span></p>
<p>The example I&#39;ll be working with will be a registration form (or a minimal part of it, anyway). The theory is that I must confirm unique email addresses in the users table so that people cannot register multiple times using the same address. This is normally part of the validation process that comes after the user submits the form to the handling PHP script. But why should the user have to wait until then for this piece of validation? Instead, as soon as the user enters their email address and goes to the next form field, the email address will be immediately validated. But to do so, I still need to query the database, which is where Ajax comes in.</p>
<p>The simplified table structure for this example could be created with the following SQL statement (without the presence of the other tables, I&#39;ve done away with identifying keys and such).</p>
<pre>CREATE TABLE users (
	email VARCHAR2(60)
)
</pre>
<p>Obviously you could expand on this in many ways. For now, though, the important thing is that the sample code assumes you have established such a table and can connect to it from a PHP script. Some records must be in this table for the example to fully function, so you should populate it like so:</p>
<pre>INSERT INTO users (email) VALUES (&#39;this@that.com&#39;)
INSERT INTO users (email) VALUES (&#39;me@school.edu&#39;)
INSERT INTO users (email) VALUES (&#39;fake@address.net&#39;)
</pre>
<p>After you&#39;ve created and populated the table, you can begin coding. As I mentioned, there are two scripts involved. To develop and test everything, you will:</p>
<ol class="bodycopy">
<li>Create the PHP script that queries the Oracle database.</li>
<li>Manually test the PHP script to see how it works.</li>
<li>Write the JavaScript code that interacts with the PHP script.</li>
<li>Make the HTML form that ties into the JavaScript.</li>
<li>Test the entire process.</li>
</ol>
<h2>Step 1: Programming the Database Query</h2>
<p>The entire PHP script is called ajax.php. (See <a class="bodylink" href="http://www.oracle.com/technology/pub/files/ullman-ajax-samples.zip">sample code zip</a>.) The purpose of this script is to run a query in Oracle and print a message based upon the results of the query. This is all very basic Oracle, SQL, and PHP, but I&#39;ll run through it to clarify what&#39;s happening.</p>
<p>The script expects to receive an email address in the URL, which is available in the variable $_GET[&#39;email&#39;]. Then the script connects to the Oracle database. The query itself counts how many records in the users table have that email address:</p>
<pre>SELECT COUNT(*) AS NUM_ROWS FROM users WHERE email=&#39;{$_GET[&#39;email&#39;]}&#39;
</pre>
<p>This should return either 0 or 1 (or nothing at all). The query is executed in Oracle and the results are bound to the PHP $rows variable. Now $rows represents how many records in the database have that email address. With respect to Ajax, the important part of the script is shown below.</p>
<pre>if ($rows &gt; 0) {
	echo &#39;Email address has already been registered!&#39;;
} else {
	echo &#39;Email address is available!&#39;;
}
</pre>
<p>One of those two messages will be printed, based upon the value of $rows. That&#39;s all there is to this page! Absolutely no HTML is needed as this script won&#39;t be used like a standard Web page.</p>
<p>If you want to improve this script, you can confirm that the email address matches a regular expression pattern for email addresses. If so, execute the query like normal; if not, echo a statement saying that it&#39;s not a valid email address. At the very least, you&#39;d likely want to prevent SQL injection attacks. (I.e., avoid using the $_GET variable in your query without some assurances of its validity.)</p>
<p>&nbsp;</p>
<h2>Step 2: Testing the PHP Script</h2>
<p>Because this entire Ajax process involves several technologies&mdash;HTML, JavaScript, PHP, SQL, and Oracle&mdash;you&#39;ll be best off testing each piece as you go. If you don&#39;t, you can easily get lost trying to find where a problem exists. Testing this PHP script should be fairly easy:</p>
<ol class="bodycopy">
<li>Make sure you&#39;ve created the table in Oracle and populated it.</li>
<li>Edit ajax.php so that it uses valid connection parameters for your Oracle installation.</li>
<li>Save the script as ajax.php.</li>
<li>Place it in the proper directory for your Web server.</li>
<li>Go to http://yoururl/ajax.php?email=X in your Web browser.</li>
</ol>
<p>In place of X, use one of the email addresses that&#39;s already in the database (e.g., http://yoururl/ajax.php?email=this@that.com). You should see the &quot;Email address has already been registered!&quot; message. Then use an email address that has not been stored. You should see the &quot;Email address is available!&quot; text. Once you have that working, you can move on to the actual Ajax aspect of this example.</p>
<p>&nbsp;</p>
<h2>Step 3: Programming the JavaScript</h2>
<p>This section of the process is probably the most difficult unless you&#39;ve done tons of JavaScript already. In any case, the JavaScript code is the heart of the Ajax process, as it performs and handles the request from the PHP page. I&#39;ll go through this code in detail.</p>
<p>The JavaScript code will define three functions. The first creates a request object variable:</p>
<pre>function createRequestObject() {
	var ro;
	if (navigator.appName == &quot;Microsoft Internet Explorer&quot;) {
		ro = new ActiveXObject(&quot;Microsoft.XMLHTTP&quot;);
	} else {
		ro = new XMLHttpRequest();
	}
	return ro;
}
</pre>
<p>You should be able to use this code for any Ajax application without modification. If the Web browser being used is Microsoft Internet Explorer, then the ro variable is initialized as an ActiveXObject of type Microsoft.XMLHTTP. For all other browsers, ro is a straightforward XMLHttpRequest type of object. That&#39;s really nothing else to it. The ro variable is now an object with all the necessary functionality to perform an asynchronous request. After creating the request object variable, this function then returns it.</p>
<p>This function is immediately called by the JavaScript code when the page is first loaded:</p>
<pre>var http = createRequestObject();
</pre>
<p>Now http represents the object and is globally available in the other functions.</p>
<p>Next up is the function that calls the PHP script:</p>
<pre>function sendRequest(email) {
	http.open(&#39;get&#39;, &#39;ajax.php?email=&#39; + encodeURIComponent(email));
	http.onreadystatechange = handleResponse;
	http.send(null);
}
</pre>
<p>This function takes one argument, which is the email address to be verified. Then it opens a connection to the PHP script. As the first argument in the open() method indicates, the request will be of type get, as opposed to post. The email address is appended to the URL, resulting in a page request like ajax.php?email=this@that.com. As you already know, this is how the PHP script is properly called. The encodeURIComponent() function just encodes the submitted value to make it URL-safe. The third line within the function tells the object what JavaScript function to call after the request has been made. The final line actually makes the request.</p>
<p>To recap, the first function, createRequestObject(), makes the object variable that&#39;s needed. The second function, sendRequest(), makes the actual request of the PHP script. Now we need a function that handles that request:</p>
<pre>function handleResponse() {
	if (http.readyState == 4) {
		document.getElementById(&#39;email_label&#39;).innerHTML = http.responseText;
	}
}
</pre>
<p>The previous function told the request object to call this function after the request has been made. This function first checks that the request was successfully made. If so, then http.readyState will be equal to 4. It could also be equal to 0 through 3 (you can search online for their actual meanings, if you care), but being equal to 4 means the request worked. The results of the request will be stored in the http.responseText attribute, the results being either of the two messages echoed by the PHP script. To be clear, if the request worked, then http.responseText will either be &quot;Email address has already been registered!&quot; or &quot;Email address is available!&quot;.</p>
<p>At this point, the JavaScript knows what the result of the PHP script was. All you need to do is get the JavaScript to notify the user of that result. An easy option would be to use an alert() box:</p>
<pre>alert(http.responseText);
</pre>
<p>If you put this within the conditional, you&#39;ll see the result when you test the whole application. (In fact, alert() is a great debugging tool to confirm what&#39;s going on in your JavaScript code.) However, I find these alerts to be annoying as an end user and would rather print the message next to the form&#39;s email input. To do so, I refer to the DOM (Document Object Model). Specifically, I assign the http.responseText to an element in my page called email_label. You&#39;ll see this in Step 4.</p>
<p>Whew! Hopefully you followed all that. To repeat, this is the most important and most complex part of this sequence. The JavaScript uses three functions to do three things: define a browser-specific request object; make a request to the PHP script; and, do something with the results of the request. If you&#39;re confused by any of this, or when it comes time to make a more complex Ajax application, you&#39;ll likely want to do a little research on JavaScript and DOM.</p>
<h2>Step 4: Making a JavaScript-functional HTML Form</h2>
<p>As I wrote previously, the premise behind this example is a registration form that takes, at the least, an email address. The minimal form would be:</p>
<pre>&lt;form action=&quot;somepage.php&quot; method=&quot;post&quot;&gt;
Email Address: &lt;input name=&quot;email&quot; type=&quot;text&quot; size=&quot;30&quot; maxlength=&quot;60&quot; /&gt;&lt;br /&gt;
First Name: &lt;input name=&quot;first_name&quot; type=&quot;text&quot; size=&quot;20&quot; maxlength=&quot;20&quot; /&gt;&lt;br /&gt;
(Rest of the form...)
&lt;/form&gt;
</pre>
<p>That&#39;s it! Well, not quite. You&#39;d want more inputs (a &quot;submit&quot; button, and so on). But for the purposes of this example, that&#39;s all you need. To avoid confusion, note that the action and method attributes here have nothing to do with the ajax.php script (which doesn&#39;t handle this form&#39;s submission).</p>
<p>Two more things are required, though. First, this form must somehow call the JavaScript code that makes the request. You could use several tricks to do that: make a clickable link, wait for the submit button to be clicked, and so on. I&#39;ve decided that once the user has entered an email address and has gone on to the next form element, the JavaScript should be called. This requires the onchange() method, which I&#39;ll add to the email input:</p>
<pre>Email Address: &lt;input name=&quot;email&quot; type=&quot;text&quot; size=&quot;30&quot; maxlength=&quot;60&quot;

onchange=&quot;sendRequest(this.form.email.value)&quot; /&gt;
</pre>
<p>As soon as the user changes the value in this input, including entering anything for the first time, and then tabs or clicks to another input, the JavaScript sendRequest() function will be called. It is fed one argument, the value of the email form input. If you look back at the JavaScript code, you can see how the value typed here gets sent to that function, which in turn is sent to the PHP script.</p>
<p>The second thing the HTML form needs is a place where JavaScript can &quot;write&quot; the received message so that it&#39;s visible to the user. As the handleResponse() function dictates, that message will be assigned to the innerHTML of an element called email_label. For this I add a span with that ID after the email address input:</p>
<pre>&lt;span id=&quot;email_label&quot;&gt;&lt;/span&gt;
</pre>
<p>That&#39;s it for tying the HTML form to the JavaScript. (See Listing 1 in the <a class="bodylink" href="http://www.oracle.com/technology/pub/files/ullman-ajax-samples.zip">sample code zip</a> for the final code.) Now it&#39;s time to see how it works!</p>
<h2>Step 5: Testing the Ajax Process</h2>
<p>Having completed the HTML and JavaScript, you should save that as ajax.html (or anything, really), then place it in the same directory as the PHP script. Load the form by running it in your Web browser, through a URL, not by opening it from the file system (i.e, go to http://yoururl/ajax.html). Type an unused email address in the proper input, then tab or click on the next input. Repeat using a stored email address.</p>
<p>The two screenshots below show the results you should see. Absolute magic!</p>
<p>&nbsp;</p>
<p><center><img alt="figure 1" src="http://www.oracle.com/technology/pub/images/ullman-ajax-f1.jpg" /></p>
<p><img alt="figure 2" src="http://www.oracle.com/technology/pub/images/ullman-ajax-f2.jpg" /></p>
<p></center></p>
<p>&nbsp;</p>
<h2>Conclusion</h2>
<p>In this article you&#39;ve seen how you can easily implement an Ajax process using PHP and Oracle. By doing so, server side validation is being accomplished within the client (although you should still keep server side validation as well, in case JavaScript is disabled). This particular example, in my opinion, demonstrates a nice feature for an end user, saving them from having to:</p>
<ul class="bodycopy" type="square">
<li>Submit the form</li>
<li>See that the email address has already been registered</li>
<li>Return to the form</li>
<li>Repeat</li>
</ul>
<p>Also, I think this example and the concept in general is kind of cool. And on the Web, that&#39;s not an insignificant factor.</p>
<p>Of course, there&#39;s tons more you can do with Ajax, PHP, and Oracle. The example in this article sent only one piece of data to the PHP script and retrieved just a string. You can send much more back and forth. If you have a significant amount of data to be returned to the calling page, you can have PHP return it in XML format, then use JavaScript to parse and display it. If you search online, you&#39;ll find many different examples.</p>
<p><strong><span class="boldbodycopy">Larry Ullman</span></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/php/creating-an-ajax-process-using-php-and-oracle-113.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Build a .NET Application on the Oracle Database with Visual Studio 2005 or 2008</title>
		<link>http://www.allfreetech.com/microsoft-net/build-a-net-application-on-the-oracle-database-with-visual-studio-2005-or-2008-115.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/build-a-net-application-on-the-oracle-database-with-visual-studio-2005-or-2008-115.html#comments</comments>
		<pubDate>Wed, 20 Jan 2010 07:31:20 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[visual studio]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=115</guid>
		<description><![CDATA[With the popularity of Microsoft&#39;s .NET Framework, many developers are hungry for information about the best means of integrating .NET applications with Oracle&#8212;not only in terms of basic connectivity, but also in relationship to effective and efficient application development using Visual Studio 2005 or 2008. In this article, I&#39;ll explain the basic yet essential processes [...]]]></description>
			<content:encoded><![CDATA[<p>With the popularity of Microsoft&#39;s .NET Framework, many developers are hungry for information about the best means of integrating .NET applications with Oracle&mdash;not only in terms of basic connectivity, but also in relationship to effective and efficient application development using Visual Studio 2005 or 2008.</p>
<p>In this article, I&#39;ll explain the basic yet essential processes involved in building a .NET application that uses an Oracle database, including:</p>
<ul type="square">
<li>How to add project references to support Oracle class libraries in your .NET project</li>
<li>How to create Oracle Database connection strings</li>
<li>How to work with Connection, Command, and DataReader objects</li>
</ul>
<p>You will have the opportunity to apply what you have learned in three <a class="bodylink" href="http://www.oracle.com/technology/pub/articles/cook-vs08.html#lab1">practice labs</a>, ranging in difficulty from the relatively simple to the more complex. The article&#39;s screenshots are taken from Visual Studio 2008, but the experience is very similar in Visual Studio 2005.</p>
<p>For information and labs about how to secure your application, see my article &quot;<a class="bodylink" href="http://www.oracle.com/technology/pub/articles/mastering_dotnet_oracle/cook_masteringdotnet.html">Securing a .NET Application on the Oracle Database</a>&quot;. (Also, see the OTN <a class="bodylink" href="http://www.oracle.com/technology/tech/dotnet/index.html">.NET Developer Center</a> for technical articles covering a range of Oracle.NET application lifecycle issues.)</p>
<p>Note that the free <a class="bodylink" href="http://www.oracle.com/technology/tech/dotnet/tools/index.html">Oracle Developer Tools for Visual Studio</a>, available for <a class="bodylink" href="http://www.oracle.com/technology/tech/dotnet/tools/index.html">download</a> from OTN, provides a Visual Studio add-in that makes the development of .NET apps on Oracle much easier and more intuitive. That subject is beyond our scope here, however.</p>
<h2>.NET Data Provider</h2>
<p>In addition to basic Oracle client connectivity software, .NET applications require the use of what is known as a <em>managed data provider</em> (where &quot;managed&quot; refers to code managed by the .NET framework). The data provider is the layer between the .NET application code and the Oracle client connectivity software. In almost every case, the best performance is achieved by using a provider optimized for a specific database platform instead of the generic .NET OLE DB data provider.</p>
<p>Oracle, Microsoft, and third-party vendors all offer .NET data providers optimized for Oracle. Oracle and Microsoft make their Oracle data providers available for free. (Microsoft&#39;s provider for the .NET Framework 2.0 is included in the framework, but it still requires Oracle client software installation.) In this article, we will use of the Oracle Data Provider for .NET (ODP.NET), which is included with the Oracle Database or as a separate <a class="bodylink" href="http://www.oracle.com/technology/software/tech/windows/odpnet/index.html">download</a>.</p>
<p>ODP.NET provides standard ADO.NET data access, while exposing Oracle database-specific features, such as XML DB, data access performance optimizations, and Real Application Clusters connection pooling.</p>
<p>When ODP.NET and Oracle client software are installed, application development using Visual Studio can begin. It&#39;s a good idea to confirm client connectivity before starting development. If you can connect to Oracle using Oracle client software such as SQL*Plus on the same machine as Visual Studio, then you know that your Oracle client-side software is properly installed and configured.</p>
<p>If you are new to Oracle, see the section &quot;Installing .NET Products&quot; in the <a class="bodylink" href="http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28843/toc.htm"><em>Oracle Database 2 Day Developer&#39;s Guide</em></a> for background information regarding installing and configuring ODP.NET specifically, or to the <a class="bodylink" href="http://www.oracle.com/technology/documentation/database.html">Oracle Database Documentation Library</a> for general information about Oracle Database.</p>
<h2>Creating a Project in Visual Studio 2005 or 2008</h2>
<p>Let&#39;s create an ODP.NET application that retrieves data from an Oracle database. Later, we&#39;ll see how to perform error handling with ODP.NET and handle an additional data retrieval scenario.</p>
<p>After starting Visual Studio, the first task is to create a project. You can either select <strong>File | New | Project</strong> as shown below or click the <strong>New Project</strong> button located directly under <strong>File</strong>.</p>
<div align="center">
<p><img alt="Figure 1" src="http://www.oracle.com/technology/pub/images/cook-vs08-f1.gif" /><br />
		<em><strong>Figure 1</strong> Creating a new project in Visual Studio 2008 Service Pack 1</em></p>
</div>
<p>A <strong>New Project</strong> dialog box appears. On the left side of the dialog box under <strong>Project Types</strong>, select the programming language of your choice. In our example, &quot;Visual Basic&quot; was chosen. On the right side under <strong>Visual Studio installed templates</strong>, choose a project template. To keep things simple, a &quot;Windows Forms Application&quot; is selected.</p>
<div align="center">
<p><img alt="Figure 2" src="http://www.oracle.com/technology/pub/images/cook-vs08-f2.gif" /><br />
		<em><strong>Figure 2</strong> Using the <strong>New Project</strong> dialog</em></p>
</div>
<p>You&#39;ll want to specify meaningful names for the project name (we used OraWinApp) and the solution name (we used OraWinApp). A solution contains one or more projects. When a solution contains only one project, many people use the same name for both.</p>
<h2>Adding a Reference</h2>
<p>Because our project must connect to an Oracle database, it is necessary to add a reference to the ODP.NET DLL containing the data provider of our choice. Within the Solution Explorer, select the project name, right click and select <strong>Add Reference</strong>. Alternatively, you can go to the menu bar and select <strong>Project</strong> and then select <strong>Add Reference</strong>.</p>
<div align="center">
<p><img alt="Figure 3" src="http://www.oracle.com/technology/pub/images/cook-vs08-f3.gif" /><br />
		<em><strong>Figure 3</strong> Adding a reference</em></p>
</div>
<p>The <strong>Add Reference</strong> dialog box appears.</p>
<div align="center">
<p><img alt="Figure 4" src="http://www.oracle.com/technology/pub/images/cook-vs08-f4.gif" /><br />
		<strong><em>Figure 4</em></strong><em> Selecting the ODP.NET Managed Data Provider</em></p>
</div>
<p>ODP.NET is found under the Oracle.DataAccess component name. Select <strong>Oracle.DataAccess</strong> from the list, then click <strong>OK</strong> to make the ODP.NET data provider known to your project.</p>
<h2>Visual Basic/C# Statements</h2>
<p>After adding references, it is standard practice to add Visual Basic Imports statements or C# using statements. Technically, these statements are not required but they do allow you to refer to database objects without using lengthy, fully qualified names.</p>
<p>By convention, these statements appear at or near the top of a code file, before the namespace or class declaration.</p>
<pre>Imports Oracle.DataAccess.Client &#39; Visual Basic ODP.NET Oracle managed provider

using Oracle.DataAccess.Client; // C# ODP.NET Oracle managed provider
</pre>
<p>If you added the reference, Intellisense will help you complete the addition of an Imports or using statement as shown in Figure 5.</p>
<div align="center">
<p><img alt="Figure 5" src="http://www.oracle.com/technology/pub/images/cook-vs08-f5.gif" /><br />
		<strong><em>Figure 5</em></strong><em> Adding an Imports statement in Visual Basic</em></p>
</div>
<h2>Connection Strings and Objects</h2>
<p>An Oracle connection string is inseparable from Oracle names resolution. Suppose you had a database alias of OraDb defined in a tnsnames.ora file as follows:</p>
<pre>OraDb=
  (DESCRIPTION=
    (ADDRESS_LIST=
      (ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521))
    )
    (CONNECT_DATA=
      (SERVER=DEDICATED)
      (SERVICE_NAME=ORCL)
    )
  )
</pre>
<p>The OraDb alias defines the database address connection information for the client. To use the OraDb alias defined in the tnsnames.ora file shown above, you would use the following syntax:</p>
<pre>Dim oradb As String = &quot;Data Source=OraDb;User Id=scott;Password=tiger;&quot; &#39; Visual Basic

string oradb = &quot;Data Source=OraDb;User Id=scott;Password=tiger;&quot;; // C#
</pre>
<p>You can modify the connection string to obviate the need for the tnsnames.ora file, however. Simply replace the name of the alias with how it would be defined in a tnsnames.ora file.</p>
<pre>&#39; Visual Basic
Dim oradb As String = &quot;Data Source=(DESCRIPTION=&quot; _
           + &quot;(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot; _
           + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot; _
           + &quot;User Id=scott;Password=tiger;&quot;

// C#
string oradb = &quot;Data Source=(DESCRIPTION=&quot;
             + &quot;(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot;
             + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot;
             + &quot;User Id=scott;Password=tiger;&quot;;
</pre>
<p>As you can see above, the username and password are embedded in the connection string in clear text. This is the simplest approach to creating a connection string. However, the clear text approach is undesirable from a security perspective. In particular, you must understand that compiled .NET application code is only marginally more secure than the clear text source code files. It is very easy to decompile .NET DLL and EXE files and view the original clear text contents. (Encryption is in fact the appropriate solution, but that subject would be a quite lengthy digression from our discussion here.)</p>
<p>Next, you must instantiate a connection object from the connection class. The connection string must be associated with the connection object.</p>
<pre>Dim conn As New OracleConnection(oradb) &#39; Visual Basic

OracleConnection conn = new OracleConnection(oradb); // C#
</pre>
<p>Notice that the connection string is associated with the connection object by being passed through the object&#39;s constructor, which is overloaded. The constructor&#39;s other overload allows the following alternative syntax:</p>
<pre>Dim conn As New OracleConnection() &#39; Visual Basic
conn.ConnectionString = oradb

OracleConnection conn = new OracleConnection(); // C#
conn.ConnectionString = oradb;
</pre>
<p>After associating a connection string with a connection object, use the Open method to make the actual connection.</p>
<pre>conn.Open() &#39; Visual Basic

conn.Open(); // C#
</pre>
<p>We&#39;ll cover error handling later.</p>
<h2>Command Object</h2>
<p>The Command object is used to specify the SQL command text that is executed, either a SQL string or a stored procedure. Similar to the Connection object, it must be instantiated from its class and it has an overloaded constructor. In this sample, ODP.NET will perform a SQL query to return the department name (DNAME) from the departments table (DEPT) where the department number (DEPTNO) is 10.</p>
<pre>Dim sql As String = &quot;select dname from dept where deptno = 10&quot; &#39; Visual Basic
Dim cmd As New OracleCommand(sql, conn)
cmd.CommandType = CommandType.Text

string sql = &quot;select dname from dept where deptno = 10&quot;; // C#
OracleCommand cmd = new OracleCommand(sql, conn);
cmd.CommandType = CommandType.Text;
</pre>
<p>Using different overloads, the syntax can be structured slightly differently. The Command object has methods for executing the command text, which will be seen in the next section. Different methods are appropriate for different types of SQL commands.</p>
<h2>Retrieving a Scalar Value</h2>
<p>Retrieving data from the database can be accomplished by instantiating an OracleDataReader object and using the ExecuteReader method, which returns an OracleDataReader object. Returned data is accessible by passing either the column name or zero-based column ordinal to the OracleDataReader.</p>
<pre>Dim dr As OracleDataReader = cmd.ExecuteReader() &#39; Visual Basic
dr.Read()

Label1.Text = dr.Item(&quot;dname&quot;) &#39; retrieve by column name
Label1.Text = dr.Item(0) &#39; retrieve the first column in the select list
Label1.Text = dr.GetString(0) &#39; return a .NET data type
Label1.Text = dr.GetOracleString(0) &#39; return an Oracle data type
</pre>
<p>There are typed accessors for returning .NET native data types and others for returning native Oracle data types, all of which are available in C#, Visual Basic, or any other .NET language. Zero-based ordinals are passed to the accessors to specify which column to return.</p>
<pre>OracleDataReader dr = cmd.ExecuteReader(); // C#
dr.Read();

label1.Text = dr[&quot;dname&quot;].ToString(); // C# retrieve by column name
label1.Text = dr.GetString(0).ToString();  // return a .NET data type
label1.Text = dr.GetOracleString(0).ToString();  // return an Oracle data type
</pre>
<p>In this simplified example, the returned value of DNAME is a string and is used to set the value of the label control&#39;s text property, which is also a string. But if DEPTNO, which is not a string, had been retrieved instead, there would be a data type mismatch. The .NET runtime attempts to implicitly convert from one data type to another when the source and destination data types don&#39;t match. Sometimes the data types are incompatible and the implicit conversion fails, throwing an exception. But even when it works, it&#39;s still better to use explicit data type conversions instead of implicit data type conversion.</p>
<p>An explicit cast to integer is shown below:</p>
<pre>Label1.Text = CStr(dr.Item(&quot;deptno&quot;)) &#39; Visual Basic integer to string cast

C# is not as forgiving as Visual Basic on implicit conversions. You&#39;ll find yourself doing explicit conversions: 

label1.Text = dr.GetInt16(&quot;deptno&quot;).ToString(); // C#
</pre>
<p>You can explicitly cast scalar values as well as arrays.</p>
<h2>Close and Dispose</h2>
<p>Either the connection object&#39;s <tt>Close</tt> or the <tt>Dispose</tt> method should be called to close the connection to the database. The <tt>Dispose</tt> method calls the <tt>Close</tt> method.</p>
<pre>conn.Close()   &#39; Visual Basic
conn.Dispose() &#39; Visual Basic

conn.Close();   // C#
conn.Dispose(); // C#
</pre>
<p>You don&#39;t have to explicitly call <tt>Close</tt> or <tt>Dispose</tt> if you use VB&#39;s <tt>Using</tt> keyword or C#&#39;s <tt>using</tt> keyword.</p>
<pre>using (OracleConnection conn = new OracleConnection(oradb)) // C#
{
    conn.Open();

    OracleCommand cmd = new OracleCommand();
    cmd.Connection = conn;
    cmd.CommandText = &quot;select dname from dept where deptno = 10&quot;;
    cmd.CommandType = CommandType.Text;

    OracleDataReader dr = cmd.ExecuteReader();
    dr.Read();

    label1.Text = dr.GetString(0);
}
</pre>
<p>In addition, OracleCommand includes a Dispose method; OracleDataReader includes a <tt>Close</tt> and <tt>Dispose</tt> method. Closing and disposing .NET objects free up system resources, ensuring more efficient application performance, which is especially important under high load conditions. You can experiment with some of the concepts we&#39;ve learned here in <a class="bodylink" href="http://www.oracle.com/technology/pub/articles/cook-vs08.html#lab1">Lab 1</a> (Retrieving Data from the Database) and <a class="bodylink" href="http://www.oracle.com/technology/pub/articles/cook-vs08.html#lab2">Lab 2</a> (Adding Interactivity).</p>
<h2>Error Handling</h2>
<p>When an error occurs, .NET applications should gracefully handle the error and inform the user with a meaningful message. Try-Catch-Finally structured error handling is a part of .NET languages; here is a relatively minimalist example of using the Try-Catch-Finally syntax:</p>
<pre>&#39; Visual Basic
Try
    conn.Open()

    Dim cmd As New OracleCommand
    cmd.Connection = conn
    cmd.CommandText = &quot;select dname from dept where deptno = &quot; + TextBox1.Text
    cmd.CommandType = CommandType.Text

    If dr.Read() Then
        Label1.Text = dr.Item(&quot;dname&quot;) &#39; or use dr.Item(0)
    End If
Catch ex As Exception &#39; catches any error
    MessageBox.Show(ex.Message.ToString())
Finally
    &#39; In a real application, put cleanup code here.
End Try

// C#
try
{
    conn.Open();

    OracleCommand cmd = new OracleCommand();
    cmd.Connection = conn;
    cmd.CommandText = &quot;select dname from dept where deptno = &quot; + textBox1.Text;
    cmd.CommandType = CommandType.Text;

    if (dr.Read()) // C#
    {
        label1.Text = dr[&quot;dname&quot;].ToString();
                   // or use dr.GetOracleString(0).ToString()
    }
}
catch (Exception ex) // catches any error
{
    MessageBox.Show(ex.Message.ToString());
}
finally
{
    // In a real application, put cleanup code here.
}
</pre>
<p>Although this approach will gracefully capture any errors in attempting to get data from the database, it is not user friendly. For example, look at the following message displayed when the database is unavailable:</p>
<div align="center">
<p><img alt="Figure 6" src="http://www.oracle.com/technology/pub/images/cook-vs08-f6.gif" /><br />
		<strong><em>Figure 6</em></strong><em> An ORA-12545 error caught and displayed to the user</em></p>
</div>
<p>An ORA-12545 is quite meaningful for an Oracle DBA or developer, but not for an end user. A better solution is to add an additional <tt>Catch</tt> statement to trap for the most common database errors and provide user-friendly messages.</p>
<pre>Catch ex As OracleException &#39; catches only Oracle errors
    Select Case ex.Number
        Case 1
            MessageBox.Show(&quot;Error attempting to insert duplicate data.&quot;)
        Case 12545
            MessageBox.Show(&quot;The database is unavailable.&quot;)
        Case Else
            MessageBox.Show(&quot;Database error: &quot; + ex.Message.ToString())
    End Select
Catch ex As Exception &#39; catches any error
    MessageBox.Show(ex.Message.ToString())

catch (OracleException ex) // catches only Oracle errors
{
    switch (ex.Number)
    {
        case 1:
            MessageBox.Show(&quot;Error attempting to insert duplicate data.&quot;);
            break;
        case 12545:
            MessageBox.Show(&quot;The database is unavailable.&quot;);
            break;
        default:
            MessageBox.Show(&quot;Database error: &quot; + ex.Message.ToString());
            break;
    }
}
catch (Exception ex) // catches any error not previously caught
{
    MessageBox.Show(ex.Message.ToString());
}
</pre>
<p>Notice the two <tt>Catch</tt> statements in the code sample above. If there aren&#39;t any Oracle errors to catch, the first statement branch is skipped, leaving any other non-Oracle error to be caught by the second statement. <tt>Catch</tt> statements must be ordered in the code from most specific to most general. After implementing the user-friendly exception handling code, the ORA-12545 error message appears as follows:</p>
<div align="center">
<p><img alt="Figure 7" src="http://www.oracle.com/technology/pub/images/cook-vs08-f7.gif" /><br />
		<strong><em>Figure 7</em></strong><em> A user-friendly error message for an ORA-12545 error</em></p>
</div>
<p>The <tt>Finally</tt> code block is always executed regardless of whether or not an error occurred. It is where cleanup code belongs. If you don&#39;t use <tt>Using</tt> or <tt>using</tt>, you should dispose your connection and other objects in the <tt>Finally</tt> code block.</p>
<h2>Retrieving Multiple Values Using a DataReader</h2>
<p>So far our examples have only showed how to retrieve a single value. An OracleDataReader can retrieve values for multiple columns and multiple rows. First consider a multiple column, single row query:</p>
<pre>select deptno, dname, loc from dept where deptno = 10
</pre>
<p>To obtain the values of the columns, either zero-based ordinals or column names can be used. Ordinals are relative to the order in the query. Thus, the LOC column&#39;s value can be retrieved in Visual Basic by using either dr.Item(2) or dr.Item(&quot;loc&quot;).</p>
<p>Here is a code snippet that concatenates the DNAME and LOC columns from the previous query:</p>
<pre>Label1.Text = &quot;The &quot; + dr.Item(&quot;dname&quot;) + &quot; department is in &quot; + dr.Item(&quot;loc&quot;) &#39; VB

label1.Text = &quot;The &quot; + dr[&quot;dname&quot;].ToString() + &quot; department is in &quot; +
              dr[&quot;loc&quot;].ToString();  // C#
</pre>
<p>Now consider a query that returns multiple rows:</p>
<pre>select deptno, dname, loc from dept
</pre>
<p>To process multiple rows returned from an OracleDataReader, some type of looping construct is needed. Furthermore, a control that can display multiple rows is desirable. An OracleDataReader is a forward-only, read-only cursor, so it can&#39;t be bound to an updateable or fully scrollable control such as a Windows Forms DataGrid control. An OracleDataReader is compatible with a ListBox control, as the following code snippet illustrates:</p>
<pre>While dr.Read() &#39; Visual Basic
   ListBox1.Items.Add(&quot;The &quot; + dr.Item(&quot;dname&quot;) + &quot; department is in &quot; + dr.Item(&quot;loc&quot;))
End While

while (dr.Read()) // C#
{
    listBox1.Items.Add(&quot;The &quot; + dr[&quot;dname&quot;].ToString() + &quot; department is in &quot; +
                       dr[&quot;loc&quot;].ToString());
}
</pre>
<p><a class="bodylink" href="http://www.oracle.com/technology/pub/articles/cook-vs08.html#lab3">Lab 3</a> (Retrieve Multiple Columns and Rows with an OracleDataReader) highlights some of these concepts.</p>
<h2>Building and Running on x64</h2>
<p>When running Visual Studio 2008 on an x64 operating system, the <strong>Active solution platform</strong> defaults to <strong>Any CPU</strong>. Change that to x86 before building your project.</p>
<div align="center">
<p><img alt="Figure 8" src="http://www.oracle.com/technology/pub/images/cook-vs08-f8.gif" /><br />
		<strong><em>Figure 8</em></strong><em> Change from <strong>Any CPU</strong> to x86 when building on a 64-bit platform</em></p>
</div>
<h2>Conclusion</h2>
<p>This article has introduced you to the process of accessing Oracle databases using .NET programming languages. You should now have the capability to connect to the database and retrieve multiple columns and rows.</p>
<p>&nbsp;</p>
<table bgcolor="#cccccc" border="0" cellpadding="4" class="bodycopy" width="100%">
<tbody>
<tr>
<td><a name="lab1"></a></p>
<h3>Lab 1: Retrieving Data from the Database</h3>
<p>We begin with the requirement that you&#39;ve created a project and added a reference as shown previously in this article.</p>
<ol>
<li>Continue by adding a button control and a label control to the Windows form. Be sure to leave room above the controls to allow additions that will be made in Lab 2.
<div align="center">
<p><img alt="Figure 9" src="http://www.oracle.com/technology/pub/images/cook-vs08-f9.gif" /><br />
								<strong><em>Figure 9</em></strong><em> Lab 1 form with button and label controls</em></p>
</p></div>
</li>
<li>Add code to retrieve data from the Oracle database and display the results on the form. Put the code in a click event handler for the button. The easiest way to get started with this task is to double click the button because it will create a stub for the event handler.
<div align="center">
<p><img alt="Figure 10" src="http://www.oracle.com/technology/pub/images/cook-vs08-f10.gif" /><br />
								<strong><em>Figure 10</em></strong><em> Click event handler stub</em></p>
</p></div>
</li>
<li>Add Visual Basic Imports statements before the Public Class declaration or C# using statements before the namespace declaration.
<pre>Imports Oracle.DataAccess.Client &#39; Visual Basic, ODP.NET Oracle managed provider

using Oracle.DataAccess.Client; // C#, ODP.NET Oracle managed provider
</pre>
</li>
<li>Add the Visual Basic version of the click event handler code between the Private Sub and End Sub statements (be sure to replace ORASRVR with your server&#39;s host name):
<pre>Dim oradb As String = &quot;Data Source=(DESCRIPTION=(ADDRESS_LIST=&quot; _
                    + &quot;(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot; _
                    + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot; _
                    + &quot;User Id=scott;Password=tiger;&quot;

Dim conn As New OracleConnection(oradb) &#39; Visual Basic
conn.Open()

Dim cmd As New OracleCommand
cmd.Connection = conn
cmd.CommandText = &quot;select dname from dept where deptno = 10&quot;
cmd.CommandType = CommandType.Text

Dim dr As OracleDataReader = cmd.ExecuteReader()
dr.Read()  &#39; replace this statement in next lab
Label1.Text = dr.Item(&quot;dname&quot;) &#39; or dr.Item(0), remove in next lab

dr.Dispose()
cmd.Dispose()
conn.Dispose()
</pre>
<p>Add the following C# code to the click event handler between the { and } curly braces for the button&#39;s click event handler (be sure to replace ORASRVR with your server&#39;s host name):
<pre>string oradb = &quot;Data Source=(DESCRIPTION=(ADDRESS_LIST=&quot;
		 + &quot;(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot;
		 + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot;
		 + &quot;User Id=scott;Password=tiger;&quot;;

OracleConnection conn = new OracleConnection(oradb); // C#
conn.Open();

OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = &quot;select dname from dept where deptno = 10&quot;;
cmd.CommandType = CommandType.Text;

OracleDataReader dr = cmd.ExecuteReader();
dr.Read();  // replace this statement in next lab
label1.Text = dr[&quot;dname&quot;].ToString();  // remove in next lab

dr.Dispose();
cmd.Dispose();
conn.Dispose();</pre>
</li>
<li>Run the application. Click the button. You should see the following:
<div align="center">
<p><img alt="Figure 11" src="http://www.oracle.com/technology/pub/images/cook-vs08-f11.gif" /><br />
								<strong><em>Figure 11</em></strong><em> Data successfully retrieved.</em></p>
</p></div>
</li>
</ol>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table bgcolor="#cccccc" border="0" cellpadding="4" class="bodycopy" width="100%">
<tbody>
<tr>
<td><a name="lab2"></a></p>
<h3>Lab 2: Adding Interactivity</h3>
<p>Now that the basics of database access are implemented in the code, the next step is to add interactivity to the application. Instead of running the hard coded query, a textbox control can be added to accept a user input for the department number (i.e., DEPTNO).</p>
<ol>
<li>Add a textbox control and another label control to the form as shown below. Set the text property of the <tt>Label2</tt> control to <tt>Enter Deptno:</tt> and make sure that the <tt>Text</tt> property of <tt>TextBox1</tt> isn&#39;t set to anything.
<div align="center">
<p><img alt="Figure 12" src="http://www.oracle.com/technology/pub/images/cook-vs08-f12.gif" /><br />
								<strong><em>Figure 12</em></strong><em> Lab 2 form with button and label controls</em></p>
</p></div>
</li>
<li>Modify the code that defines the select string:
<pre>cmd.CommandText = &quot;select dname from dept where deptno = &quot; + TextBox1.Text &#39;VB

cmd.CommandText = &quot;select dname from dept where deptno = &quot; + textBox1.Text; // C#&gt;</pre>
</li>
<li>Run the application. Test the application by entering 10 for the DEPTNO. Retest the application by entering an invalid DEPTNO (e.g., 50). The application will abort.
<div align="center">
<p><img alt="Figure 13" src="http://www.oracle.com/technology/pub/images/cook-vs08-f13.gif" /><br />
								<strong><em>Figure 13</em></strong><em> An unhandled exception</em></p>
</p></div>
</li>
<li>Modify your code to prevent an error when an invalid DEPTNO is entered. Recall that the ExecuteReader method actually returns an object. Replace the line containing dr.Read with all of the following statements.
<pre>If dr.Read() Then &#39; Visual Basic
    Label1.Text = dr.Item(&quot;dname&quot;).ToString()
Else
    Label1.Text = &quot;deptno not found&quot;
End If

if (dr.Read()) // C#
{
    label1.Text = dr[&quot;dname&quot;].ToString();;
}
else
{
    label1.Text = &quot;deptno not found&quot;;
}
</pre>
<p>Test the application by entering a DEPTNO that does not exist. Now the application no longer aborts. Enter the letter A instead of a number and click the button. The application aborts. Clearly, our application needs a better approach to handling errors.</p>
<p>Although it could be argued that the application should not allow the user to make invalid inputs that would cause an error, ultimately the application must have robust error handling added. Not all errors are preventable, so error handling must be implemented.</p>
</li>
</ol>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table bgcolor="#cccccc" border="0" cellpadding="4" class="bodycopy" width="100%">
<tbody>
<tr>
<td><a name="lab3"></a></p>
<h3>Lab 3: Retrieve Multiple Columns and Rows with an OracleDataReader</h3>
<p>Now that a single value has been retrieved, the next step is to retrieve multiple columns and rows with an OracleDataReader. A ListBox control is added to the form to display the results.</p>
<ol>
<li>Add a ListBox control to the form. Resize the control to fill most of the width of the form as shown below.
<div align="center">
<p><img alt="Figure 14" src="http://www.oracle.com/technology/pub/images/cook-vs08-f14.gif" /><br />
								<strong><em>Figure 14</em></strong><em> Form with ListBox added</em></p>
</p></div>
</li>
<li>Remove the where clause from the query and add the additional columns:
<pre>cmd.CommandText = &quot;select deptno, dname, loc from dept&quot; &#39; Visual Basic

cmd.CommandText = &quot;select deptno, dname, loc from dept&quot;; // C#</pre>
</li>
<li>The query results will be read in a while loop and will populate the ListBox control. Modify your Visual Basic code to look like this:
<pre>Dim oradb As String = &quot;Data Source=(DESCRIPTION=(ADDRESS_LIST=&quot; _
            + &quot;(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot; _
            + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot; _
            + &quot;User Id=scott;Password=tiger;&quot;

Dim conn As New OracleConnection(oradb) &#39; Visual Basic
conn.Open()

Dim cmd As New OracleCommand
cmd.Connection = conn
cmd.CommandText = &quot;select deptno, dname, loc from dept&quot;
cmd.CommandType = CommandType.Text

Dim dr As OracleDataReader = cmd.ExecuteReader()
While dr.Read()
    ListBox1.Items.Add(&quot;The &quot; + dr.Item(&quot;dname&quot;) + _
                       &quot; department is in &quot; + dr.Item(&quot;loc&quot;))
End While

dr.Dispose()
cmd.Dispose()
conn.Dispose()
Modify your C# code to look like this:
string oradb = &quot;Data Source=(DESCRIPTION=(ADDRESS_LIST=&quot;
                + &quot;(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot;
                + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot;
                + &quot;User Id=scott;Password=tiger;&quot;;

OracleConnection conn = new OracleConnection(oradb); // C#
conn.Open();

OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = &quot;select deptno, dname, loc from dept&quot;;
cmd.CommandType = CommandType.Text;

OracleDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
   listBox1.Items.Add(&quot;The &quot; + dr[&quot;dname&quot;].ToString() +
                      &quot; department is in &quot; + dr[&quot;loc&quot;].ToString());
}

dr.Dispose();
cmd.Dispose();
conn.Dispose();</pre>
</li>
<li>Run the application. The ListBox should be populated with all of the department names and locations from the DEPT table. The code downloads have error handling implemented.</li>
</ol>
</td>
</tr>
</tbody>
</table>
<hr />
<p><strong>John Paul Cook</strong> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/build-a-net-application-on-the-oracle-database-with-visual-studio-2005-or-2008-115.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Write messaging applications with ODP.NET and Oracle Streams Advanced Queuing</title>
		<link>http://www.allfreetech.com/microsoft-net/write-messaging-applications-with-odp-net-and-oracle-streams-advanced-queuing-119.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/write-messaging-applications-with-odp-net-and-oracle-streams-advanced-queuing-119.html#comments</comments>
		<pubDate>Tue, 19 Jan 2010 07:39:13 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[oracle]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=119</guid>
		<description><![CDATA[Applications frequently need to pass messages to each other, and they need to do so reliably and often asynchronously. This goal is typically achieved with queuing: producer applications enqueue messages, and consumer applications dequeue messages. A message stays in the queue until a consumer application dequeues it or the message expires. Oracle Streams Advanced Queuing [...]]]></description>
			<content:encoded><![CDATA[<p><span class="bodycopy">Applications frequently need to pass messages to each other, and they need to do so reliably and often asynchronously. This goal is typically achieved with queuing: producer applications enqueue messages, and consumer applications dequeue messages. A message stays in the queue until a consumer application dequeues it or the message expires.<span id="more-119"></span></span></p>
<p><span class="bodycopy">Oracle Streams Advanced Queuing provides database-integrated message queuing functionality. Because Oracle Streams Advanced Queuing is implemented in database tables, queue data enjoys the Oracle Database benefits of high availability, scalability, and reliability. </span></p>
<p><span class="bodycopy">Oracle Data Provider for .NET (ODP.NET), Oracle&rsquo;s ADO.NET-compliant data provider, includes Oracle Streams Advanced Queuing classes to expose the messaging capabilities of Oracle Streams Advanced Queuing. Oracle Developer Tools for Visual Studio, a plug-in for Microsoft Visual Studio 2008 and Visual Studio 2005, includes administration tools that assist with tasks such as creating and modifying queues and queue tables.</span></p>
<p><span class="bodycopy">This article guides you through creating a set of .NET applications that make up a stock ticker system that demonstrates many Oracle Streams Advanced Queuing features. You will first create a queue in Oracle Database that holds stock ticker symbols and the corresponding stock prices. Every time a stock price changes, it will be loaded onto this queue by the StockQueueLoader application that you create next. You will also create the StockTickerListener application that receives notifications whenever a new stock price arrives in the queue and then retrieves the stock information and displays it on a ticker screen. StockTickerListener can receive notifications for all stocks that are loaded in the queue, but the queue can also be configured with rules specifying that StockTickerListener receives notifications only when specific stocks and, optionally, price ranges for specific stocks are loaded in the queue. To make it easy for a user to dynamically modify these rules, you will also run a helper application called StockQueueSubscriberAdmin.</span></p>
<p><strong><span class="parahead1">Setup</span> </strong></p>
<p><span class="bodycopy">To follow along with the steps in this article, you will need the following:</span></p>
<p>&nbsp;</p>
<ul>
<li><span class="bodycopy">SYSDBA privileges for Oracle Database Release 9.2 or later, which may be required to grant some of the Oracle Streams Advanced Queuing privileges</span></li>
<li><span class="bodycopy">Microsoft Visual Studio 2008 or Visual Studio 2005</span></li>
<li><span class="bodycopy">Oracle Developer Tools for Visual Studio and Oracle Data Provider for .NET Release 11.1.7.10 or later</span></li>
</ul>
<p><span class="bodycopy">Before you build the sample applications, you will create connections to Oracle Database from Visual Studio and grant the appropriate privileges to enable the use of queuing.</span></p>
<p><span class="bodycopy">To connect to Oracle Database from Visual Studio, create a new connection in </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy">, the top-level node of Server Explorer. (If Server Explorer is not yet visible, select </span><span class="boldbodycopy">View</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Server Explorer</span><span class="bodycopy"> from the main menu.)</span></p>
<p><span class="bodycopy">Right-click </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy">, and select </span><span class="boldbodycopy">Add Connection</span><span class="bodycopy">. In the dialog box that appears, confirm that </span><span class="boldbodycopy">Oracle Database (Oracle ODP.NET)</span><span class="bodycopy"> appears in the </span><span class="boldbodycopy">Data source</span><span class="bodycopy"> field. If you do not see </span><span class="boldbodycopy">Oracle Database (Oracle ODP.NET)</span><span class="bodycopy">, click the </span><span class="boldbodycopy">Change</span><span class="bodycopy"> button and select </span><span class="boldbodycopy">Oracle Data Provider for .NET</span><span class="bodycopy"> from the list of providers. Select the database you want to connect to from the </span><span class="boldbodycopy">Datasource name</span><span class="bodycopy"> list. Click </span><span class="boldbodycopy">Use a specific user name and password</span><span class="bodycopy">. In the </span><span class="boldbodycopy">User name</span><span class="bodycopy"> field, enter SYS. In the </span><span class="boldbodycopy">Password</span><span class="bodycopy"> field, enter the password for SYS, and ensure that </span><span class="boldbodycopy">Role</span><span class="bodycopy"> is set to </span><span class="boldbodycopy">SYSDBA</span><span class="bodycopy">. Click </span><span class="boldbodycopy">Test connection</span><span class="bodycopy"> to verify that you can connect, and click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to complete the connection setup.</span></p>
<p><span class="bodycopy">To create and modify queues and queue tables and to enqueue and dequeue from them, you need the EXECUTE privilege on the DBMS_AQ and DBMS_AQADM PL/SQL packages. (If you wanted to modify queues you did not create, you would also require privileges on the AQ_ADMINISTRATOR_ROLE role.) You will grant the required privileges, using the Grant/Revoke Privilege dialog box in Visual Studio.</span></p>
<p><span class="bodycopy">Right-click the </span><span class="boldbodycopy">SYS</span><span class="bodycopy"> connection node, and choose </span><span class="boldbodycopy">Privileges</span><span class="bodycopy"> from the context menu. In the Grant/Revoke Privileges dialog box that appears, set </span><span class="boldbodycopy">Object Type</span><span class="bodycopy"> to </span><span class="boldbodycopy">Package</span><span class="bodycopy">. Leave </span><span class="boldbodycopy">Schema</span><span class="bodycopy"> set to </span><span class="boldbodycopy">SYS</span><span class="bodycopy">. Click the first radio button, labeled </span><span class="boldbodycopy">Grant/Revoke privileges to a user/role on one or more database object(s)</span><span class="bodycopy">. Hold down the Ctrl key, and in the </span><span class="boldbodycopy">Object Names</span><span class="bodycopy"> list, highlight both </span><span class="boldbodycopy">DBMS_AQ</span><span class="bodycopy"> and </span><span class="boldbodycopy">DBMS_AQADM</span><span class="bodycopy">. From the </span><span class="boldbodycopy">User/Role</span><span class="bodycopy"> list, select </span><span class="boldbodycopy">User</span><span class="bodycopy"> and choose </span><span class="boldbodycopy">HR</span><span class="bodycopy"> or some other username. In the list of privileges, in the Grant column, check the check box next to the </span><span class="boldbodycopy">EXECUTE</span><span class="bodycopy"> privilege. Click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to accept the changes, and close the dialog box.</span></p>
<p><span class="bodycopy">Now connect to Oracle Database as HR (or whichever user you just granted the Oracle Streams Advanced Queuing package privileges). In Server Explorer, right-click </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy"> and select </span><span class="boldbodycopy">Add Connection</span><span class="bodycopy">. Follow the same steps to connect as HR that you used to connect as SYS, except to set </span><span class="boldbodycopy">Role</span><span class="bodycopy"> to </span><span class="boldbodycopy">Default</span><span class="bodycopy">.</span></p>
<p><strong><span class="parahead1">Creating the STOCK User-Defined Type</span> </strong></p>
<p><span class="bodycopy">Oracle Database queues typically hold objects of a single type (unless they are defined as ANYTYPE queues) and can be an XMLType, a user-defined type (UDT), or a RAW type. For more information on Oracle Streams Advanced Queuing queue types, including the benefits and limitations of each, see the <a href="http://download.oracle.com/docs/cd/B28359_01/server.111/b28420/toc.htm" target="_blank"><span class="bodylink"><i>Oracle Streams Advanced Queuing User&rsquo;s Guide</i></span></a>.</span></p>
<p><span class="bodycopy">The queue for this article will be made up of a user-defined type called STOCK, whose definition will include a stock symbol name as well as the price of the stock. (For a deep dive into Oracle user-defined types with Visual Studio and .NET, see &ldquo;<a href="http://www.oracle.com/technology/oramag/oracle/08-may/o38net.html" target="_blank"><span class="bodylink">It Takes All Types</span></a>&rdquo; in the May/June 2008 issue of </span><span class="italicbodycopy">Oracle Magazine</span><span class="bodycopy">).</span></p>
<p><span class="bodycopy">To create the user-defined type, in Server Explorer, under the HR data connection, right-click the </span><span class="boldbodycopy">User Defined Types</span><span class="bodycopy"> node and choose </span><span class="boldbodycopy">New Object Type</span><span class="bodycopy"> from the menu. This will launch Object Designer. In the </span><span class="boldbodycopy">Type name</span><span class="bodycopy"> field, enter </span><tt>STOCK</tt><span class="bodycopy">. Click the </span><span class="boldbodycopy">Add</span><span class="bodycopy"> button to add an attribute, and in the Attribute Properties </span><span class="boldbodycopy">Name</span><span class="bodycopy"> field, enter </span><tt>SYMBOL</tt><span class="bodycopy">. From the </span><span class="boldbodycopy">Type</span><span class="bodycopy"> list, choose </span><span class="boldbodycopy">VARCHAR2</span><span class="bodycopy">. Click the </span><span class="boldbodycopy">Add</span><span class="bodycopy"> button again to add another attribute. In the </span><span class="boldbodycopy">Name</span><span class="bodycopy"> field for this new attribute, enter </span><tt>PRICE</tt><span class="bodycopy"> and choose </span><span class="boldbodycopy">NUMBER</span><span class="bodycopy"> from the </span><span class="boldbodycopy">Type</span><span class="bodycopy"> list. Click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to create the type. The type will now be visible in Server Explorer under the </span><span class="boldbodycopy">User Defined Types</span><span class="bodycopy"> node and will also be available in datatype lists in various Oracle designers, such as Queue Designer. </span></p>
<p><span class="parahead1">Creating the Queue and the Queue Table</span></p>
<p><span class="bodycopy">Next, create a queue named STOCK_Q and its queue table, STOCK_QTAB. Under the </span><span class="boldbodycopy">HR</span><span class="bodycopy"> data connection node in Server Explorer, expand the </span><span class="boldbodycopy">Advanced Queues</span><span class="bodycopy"> node, which will expose the </span><span class="boldbodycopy">Queues</span><span class="bodycopy"> and </span><span class="boldbodycopy">Queue Tables</span><span class="bodycopy"> collection nodes (see Figure 1). Right-click the </span><span class="boldbodycopy">Queues</span><span class="bodycopy"> node, and select </span><span class="boldbodycopy">New Queue</span><span class="bodycopy"> from the menu. This will launch Queue Designer (see Figure 2).</span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 1" border="0" height="511" src="http://www.oracle.com/technology/oramag/oracle/09-nov/images/o69net_f1.gif" width="481" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 1: Server Explorer Advanced Queues and User-Defined Types nodes (left); Queues node context menu (right) </span></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 2" border="0" height="595" src="http://www.oracle.com/technology/oramag/oracle/09-nov/images/o69net_f2.gif" width="473" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 2: Queue Designer </span></td>
</tr>
</tbody>
</table>
<p><span class="bodycopy">In the </span><span class="boldbodycopy">Queue name</span><span class="bodycopy"> field, enter </span><tt>STOCK_Q</tt><span class="bodycopy">. From the </span><span class="boldbodycopy">Queue type</span><span class="bodycopy"> list, choose </span><span class="boldbodycopy">Normal Queue</span><span class="bodycopy">. For </span><span class="boldbodycopy">Payload Type</span><span class="bodycopy">, click the </span><span class="boldbodycopy">Complex</span><span class="bodycopy"> radio button, and then from the list next to it, choose the </span><span class="boldbodycopy">STOCK</span><span class="bodycopy"> user-defined type. </span></p>
<p><span class="bodycopy">Click the </span><span class="boldbodycopy">Queue Table</span><span class="bodycopy"> tab in the lower half of the designer. In the </span><span class="boldbodycopy">Queue Table</span><span class="bodycopy"> area, click the </span><span class="boldbodycopy">New</span><span class="bodycopy"> radio button and enter </span><tt>STOCK_QTAB</tt><span class="bodycopy"> as the name of the queue table. Leave the rest of the default settings as they are. (The most important settings are the </span><span class="boldbodycopy">Multi-Consumer</span><span class="bodycopy"> and </span><span class="boldbodycopy">Secure</span><span class="bodycopy"> check boxes, which must be checked, because multiple stock ticker applications can be run at the same time and all of them will need access to the contents of the queue.)</span></p>
<p><span class="bodycopy">Still in the Queue Designer, click the </span><span class="boldbodycopy">Subscribers</span><span class="bodycopy"> tab. Click the grid in the lower half of the designer, which will cause </span><tt>SUBSCRIBER1</tt><span class="bodycopy"> to be entered for </span><span class="boldbodycopy">Consumer Name</span><span class="bodycopy">. Leave the </span><span class="boldbodycopy">Rule</span><span class="bodycopy"> field blank. Click a new line in the grid to create another subscriber entry. Change the name of this one from </span><tt>SUBSCRIBER2</tt><span class="bodycopy"> to </span><tt>DEFAULT</tt><span class="bodycopy">. Leave the rule for this subscriber entry blank. </span></p>
<p><span class="bodycopy">Click </span><span class="boldbodycopy">Save</span><span class="bodycopy"> to create the queue and the queue table. The STOCK_Q queue and the STOCK_QTAB queue table will now be visible in Server Explorer (see Figure 1). The designer automatically starts the queue after creating it. </span></p>
<p><span class="bodycopy">Note that an exception queue named AQ$_STOCK_QTAB_E has been automatically created for you and that the exceptions will be stored in the STOCK_QTAB queue table. Oracle Streams Advanced Queuing exceptions are generated in a variety of circumstances, such as when a message expires before it is dequeued. For more information on Oracle Streams Advanced Queuing exceptions, see </span><span class="italicbodycopy">Oracle Streams Advanced Queuing User&rsquo;s Guide. </span></p>
<p><strong><span class="parahead1">Building the StockQueueLoader Application</span> </strong></p>
<p><span class="bodycopy">With the queue and the queue table created, you will now build the StockQueueLoader application that generates fictional stock price fluctuations in a fantasy stock market consisting of 10 ticker symbols and loads these stock prices (using a STOCK user-defined type) into the STOCK_Q queue you just created. (In a real-world scenario, actual stock price updates could be obtained via Web services and then inserted into an Oracle queue.) </span></p>
<p><span class="bodycopy">(Note that all of the applications created and used in this article&mdash;StockQueueLoader, StockTickerListener, and QueueSubscriberAdmin&mdash;are available prebuilt in the article&rsquo;s <a href="http://www.oracle.com/technology/oramag/oracle/09-nov/o69odt.zip"><span class="bodylink">application download</span></a>.)</span></p>
<p><span class="bodycopy">To begin construction of the queue loader application (StockQueueLoader), choose </span><span class="boldbodycopy">File</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">New</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Project</span><span class="bodycopy"> from the main menu. In the dialog box that appears, under Project type Visual C#, choose </span><span class="boldbodycopy">Windows</span><span class="bodycopy">, and then on the right side of the dialog box, choose the </span><span class="boldbodycopy">Console Application</span><span class="bodycopy"> template. In the </span><span class="boldbodycopy">Name</span><span class="bodycopy"> field, enter </span><tt>StockQueueLoader.</tt></p>
<p><span class="bodycopy">In the newly opened project, go to Solution Explorer; right-click the </span><span class="boldbodycopy">ConsoleApplication</span><span class="bodycopy"> project; and from the menu, choose </span><span class="boldbodycopy">Add Reference</span><span class="bodycopy">. On the </span><span class="boldbodycopy">.NET</span><span class="bodycopy"> tab in the Add Reference dialog box, scroll down until you see the Oracle.DataAccess assembly. You may see multiple versions, but select version 2.111.7.10&mdash;the version in which Oracle Streams Advanced Queuing support was first introduced&mdash;or later.</span></p>
<p><span class="bodycopy">Next, download the sample applications at <a href="http://www.oracle.com/technology/oramag/oracle/09-nov/o69odt.zip"><span class="bodylink">otn.oracle.com/oramag/oracle/09-nov/o69odt.zip</span></a>, unzip the file, and copy the contents of the AQ_ORAMAG\CodeListings\aqloader.txt file on top of the default template code. (Excerpts of the new code appear in Listing 1.) Notice that the key ODP.NET classes being used are OracleAQQueue and OracleAQMessage. Furthermore, note that the payload for the OracleAQMessage class is another .NET class called STOCK. STOCK is the .NET custom class for the STOCK Oracle user-defined type. (Custom classes enable .NET code to pass user-defined type values to and from Oracle Database.)</span></p>
<p><span class="boldbodycopy">Code Listing 1:</span><span class="bodycopy"> StockQueueLoader application code excerpt</span></p>
<p>&nbsp;</p>
<pre>OracleAQQueue queue = new OracleAQQueue(&quot;HR.STOCK_Q&quot;, con);
queue.MessageType = OracleAQMessageType.Udt;
queue.EnqueueOptions.Visibility = OracleAQVisibilityMode.Immediate;
OracleAQMessage enqMsg = new OracleAQMessage();

Console.WriteLine(&quot;Connected to Oracle.... Will start enqueuing in 10 seconds&quot;);
System.Threading.Thread.Sleep(10000);

string[] symbols = new string[10] { &quot;ORCL&quot;, &quot;MSFT&quot;, &quot;INTC&quot;, &quot;CSCO&quot;, &quot;ADBE&quot;, &quot;GOOG&quot;, &quot;AAPL&quot;, &quot;AMZN&quot;, &quot;EBAY&quot;, &quot;JAVA&quot; };

double[] prices = new double[10] { 19.5, 19, 18.25, 15, 24, 383.25, 121, 79.75, 15, 9 };

Random rand = new Random();
while (true)
{
    for (int i = 0; i &lt; 10; i++)
    {
        //...code to randomly increase or decrease prices[i] goes here
        }

        //We don&#39;t want multiple copies of the same stock on the queue
        //at the same time, so the message will expire after 5 seconds
        enqMsg.Expiration = 5;

        enqMsg.SenderId = new OracleAQAgent(&quot;QUEUELOADER&quot;);
        enqMsg.Payload = new STOCK(symbols[i], (decimal)prices[i]);
        queue.Enqueue(enqMsg);
</pre>
<p><span class="bodycopy">Now generate the STOCK custom class from the STOCK user-defined type, by using a wizard. To start the wizard, in Server Explorer, under the HR data connection, expand the </span><span class="boldbodycopy">User-Defined Types</span><span class="bodycopy"> node (see Figure 1). Find and right-click the </span><span class="boldbodycopy">STOCK</span><span class="bodycopy"> node. From the menu, choose </span><span class="boldbodycopy">Generate Custom Class</span><span class="bodycopy">. In the wizard, click </span><span class="boldbodycopy">Next</span><span class="bodycopy"> to move past the splash screen. In the next screen, uncheck the </span><span class="boldbodycopy">Inherit from Project</span><span class="bodycopy"> check box, directly above the </span><span class="boldbodycopy">Namespace</span><span class="bodycopy"> field. Then change </span><tt>Namespace</tt><span class="bodycopy"> to </span><tt>Stock</tt><span class="bodycopy">, click </span><span class="boldbodycopy">Next</span><span class="bodycopy"> until you get to the final screen, and click the </span><span class="boldbodycopy">Finish</span><span class="bodycopy"> button. This will generate a Stock.cs file and place it in your project.</span></p>
<p><span class="bodycopy">Now add the following constructor to the Stock class, below the automatically generated constructors: </span></p>
<p>&nbsp;</p>
<pre>public STOCK(string sym, decimal pr)
{
   SYMBOL = sym;
   PRICE = pr;
}
</pre>
<p><span class="bodycopy">Finally, build the application, by selecting </span><span class="boldbodycopy">Build</span><span class="bodycopy"> from the Visual Studio main menu and then selecting </span><span class="boldbodycopy">Rebuild Solution</span><span class="bodycopy">. Run the application, by choosing </span><span class="boldbodycopy">Debug</span><span class="bodycopy"> from the main menu, and then select </span><span class="boldbodycopy">Run Without Debugging</span><span class="bodycopy">.</span></p>
<p><span class="bodycopy">As you see messages appear in the console indicating that stock prices are being loaded into the queue, you can inspect the STOCK_QTAB table in Oracle Database to see these values being added there. In Server Explorer, under the </span><span class="boldbodycopy">HR</span><span class="bodycopy"> data connection, expand the </span><span class="boldbodycopy">Tables</span><span class="bodycopy"> node and double-click the </span><span class="boldbodycopy">STOCK_QTAB</span><span class="bodycopy"> node to open the data window. If you right-click the data window and choose </span><span class="boldbodycopy">Refresh</span><span class="bodycopy"> from the context menu, you can watch this queue table grow and notice that after five seconds, each entry in this table is replaced with an advanced queuing exception. Because the StockQueueLoader .NET code sets an expiration of five seconds for each item loaded into the queue, these exceptions indicate that the item was not dequeued before this expiration.</span></p>
<p><strong><span class="parahead1">Building the StockTickerListener Application</span> </strong></p>
<p><span class="bodycopy">Consumer applications have several options for finding out if there is something in a queue they are interested in. They can poll a queue by inspecting it from time to time to see if there is a message they need; they can listen to the queue with a dedicated thread; or they can register a </span><span class="italicbodycopy">callback</span><span class="bodycopy">, a subroutine that gets called and is passed a notification when a message that meets certain criteria is put into the queue.</span></p>
<p><span class="bodycopy">There are various ways a consumer application can choose whether a message is of interest. Messages can be addressed to specific recipients or recipient groups. Messages can also be assigned </span><span class="italicbodycopy">correlations</span><span class="bodycopy">, which are ad hoc identifiers assigned by the producing applications. Messages also have priorities for filtering. Finally, messages can be inspected via </span><span class="italicbodycopy">rules</span><span class="bodycopy">, which are essentially WHERE clauses added to SELECT statements that query against the queue. </span></p>
<p><span class="bodycopy">A consumer application can specify an interest in certain messages in a queue by becoming a subscriber. Each subscriber can define a named rule. You will now build an application&mdash;StockTickerListener&mdash;that receives callbacks whenever stock prices appear in the queue that match a subscriber rule. These stock prices will be output to a window much like a stock ticker. </span></p>
<p><span class="bodycopy">To build the StockTickerListener application, in a new instance of Visual Studio, first create a new console application, including an Oracle.DataAccess reference (in the same way you did in the previous section). Now add the Stock.cs custom class file (from the StockQueueLoader application) to your new project, by right-clicking the new project name in Solution Explorer, choosing </span><span class="boldbodycopy">Add an Existing Item</span><span class="bodycopy">, and then browsing to the file. Visual Studio will then make a local copy of that file in your project, saving you the trouble of re-creating it.</span></p>
<p><span class="boldbodycopy">Code Listing 2:</span><span class="bodycopy"> StockTickerListener application code excerpt</span></p>
<p>&nbsp;</p>
<pre>OracleAQQueue queue = new OracleAQQueue(&quot;HR.STOCK_Q&quot;, con);
queue.MessageType = OracleAQMessageType.Udt;
queue.NotificationConsumers = new string[1] { &quot;SUBSCRIBER1&quot; };

queue.MessageAvailable +=
  new OracleAQMessageAvailableEventHandler(QueueCallback.MsgReceived);
.....

static void MsgReceived(object src, OracleAQMessageAvailableEventArgs arg)
{
    try
    {
        Console.WriteLine(&quot;Notification Received...&quot;);
        byte[] notifiedMsgId = arg.MessageId[0];

        OracleConnection con = new OracleConnection(constr);
        con.Open();

        // Prepare to dequeue message by its MessageID
        OracleAQQueue queue = new OracleAQQueue(&quot;HR.STOCK_Q&quot;, con);
        queue.MessageType = OracleAQMessageType.Udt;
        queue.UdtTypeName = &quot;HR.STOCK&quot;;
        queue.DequeueOptions.MessageId = notifiedMsgId;
        queue.DequeueOptions.ConsumerName = &quot;SUBSCRIBER1&quot;; 

        queue.DequeueOptions.DequeueMode = OracleAQDequeueMode.Browse;

        //Dequeue
        OracleAQMessage deqMsg = queue.Dequeue();
        STOCK st = (deqMsg.Payload as STOCK);

        Console.WriteLine(st.SYMBOL + &quot;: &quot; + st.PRICE);
</pre>
<p><span class="bodycopy">From the sample applications you downloaded earlier, copy the contents of the AQ_ORAMAG\CodeListings\stocktickerlistener.txt file on top of the console template code. (Excerpts of this code appear in Listing 2.) The main part of the code contains two key methods. The first is </span></p>
<p>&nbsp;</p>
<pre>queue.NotificationConsumers
</pre>
<p><span class="bodycopy">which is set to SUBSCRIBER1. This indicates that callbacks should be received only when the SUBSCRIBER1 subscription rules are satisfied. The second key method is</span></p>
<p>&nbsp;</p>
<pre>
queue.MessageAvailable += new
OracleAQMessageAvailableEventHandler
(QueueCallback.MsgReceived);
</pre>
<p><span class="bodycopy">This registers the MsgReceived method as a callback.</span></p>
<p><span class="bodycopy">In the code for the MsgReceived callback, note that the advanced queuing AQ MessageID is included as part of the arguments that are passed to the method. This ID is set to </span></p>
<p>&nbsp;</p>
<pre>queue.DequeueOptions.MessageId
</pre>
<p><span class="bodycopy">to specify the message you want. Finally, </span></p>
<p>&nbsp;</p>
<pre>queue.DequeueOptions.DequeueMode = OracleAQDequeueMode.Browse
</pre>
<p><span class="bodycopy">indicates that the message should not be removed from the queue after viewing, because other client applications may need to view that stock.</span></p>
<p><span class="bodycopy">Build this application, by selecting </span><span class="boldbodycopy">Build</span><span class="bodycopy"> from the Visual Studio main menu and then selecting </span><span class="boldbodycopy">Rebuild Solution</span><span class="bodycopy">. Run the application, by choosing </span><span class="boldbodycopy">Debug</span><span class="bodycopy"> from the main menu, and then select </span><span class="boldbodycopy">Run Without Debugging</span><span class="bodycopy">. </span></p>
<p><span class="bodycopy">Now go back to the earlier instance of Visual Studio, rerun the StockQueueLoader application, and place both console application windows side by side. You should see the StockTickerListener application display every stock price that is loaded by the StockQueueLoader application (see Figure 3). This is because SUBSCRIBER1&rsquo;s rule is currently set to null. Because these rules are essentially WHERE clauses in a query over the queue contents, a null rule means that every item on the queue will be included. Keep both applications running while you move on to the next section.</span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 3" border="0" height="584" src="http://www.oracle.com/technology/oramag/oracle/09-nov/images/o69net_f3.gif" width="393" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 3: StockQueueLoader (top) and StockTickerListener (bottom) </span></td>
</tr>
</tbody>
</table>
<p><strong><span class="parahead1">Modifying a SUBSCRIBER Rule at Runtime</span> </strong></p>
<p><span class="bodycopy">Earlier, you saw a subscriber rule in the Queue Designer in Visual Studio. This rule selects specific STOCK user-defined type stock symbols and enables users to specify a range of stock prices in which they are interested. Now you will run a helper application that makes it easier to change this rule at runtime while the stock ticker application is running. </span></p>
<p><span class="bodycopy">The download provided with this article includes a Windows Forms application called StockQueueSubscriberAdmin.This application presents a user interface (see Figure 4) that includes a list of stock symbols; an optional field for providing a stock price; and a list of conditions that enables the user to set up a subscriber rule for receiving stock prices that are less than, greater than, or equal to the provided value. </span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 4" border="0" height="455" src="http://www.oracle.com/technology/oramag/oracle/09-nov/images/o69net_f4.gif" width="650" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 4: StockQueueSubscriberAdmin user interface </span></td>
</tr>
</tbody>
</table>
<p><span class="bodycopy">Run the StockQueueSubscriberAdmin application. Select the </span><span class="boldbodycopy">ORCL</span><span class="bodycopy"> symbol from the stock list, and click </span><span class="boldbodycopy">Add to Rule</span><span class="bodycopy">. In the text box, you will see </span></p>
<p>&nbsp;</p>
<pre>tab.user_data.SYMBOL=&#39;&#39;ORCL&#39;&#39;
</pre>
<p><span class="bodycopy">This rule will cause your stock ticker to receive notifications only when ORCL stock values are placed in the queue. Next, select the </span><span class="boldbodycopy">JAVA</span><span class="bodycopy"> symbol from the list and enter </span><tt>3</tt><span class="bodycopy"> in the </span><span class="boldbodycopy">Price</span><span class="bodycopy"> field. Choose &gt; (greater than) from the </span><span class="boldbodycopy">Condition</span><span class="bodycopy"> list. Click </span><span class="boldbodycopy">Add to Rule</span><span class="bodycopy">. Now the text box contains</span></p>
<p>&nbsp;</p>
<pre>tab.user_data.SYMBOL=&#39;&#39;ORCL&#39;&#39; OR
(tab.user_data.SYMBOL=&#39;&#39;JAVA&#39;&#39; AND
tab.user_data.PRICE&gt;3)
</pre>
<p><span class="bodycopy">This rule will cause your stock ticker to receive notifications when all ORCL stock prices as well as any JAVA prices above $3 are loaded into the queue.</span></p>
<p><span class="bodycopy">Finally, click </span><span class="boldbodycopy">Alter Subscription!</span><span class="bodycopy">. This will execute the DBMS_AQADM.ALTER_SUBSCRIBER procedure and pass the rule you have created. (The code that calls this procedure is shown in Listing 3.) To see the new rule, in Server Explorer right-click the </span><span class="boldbodycopy">STOCK_Q</span><span class="bodycopy"> node, choose </span><span class="boldbodycopy">Design Queue</span><span class="bodycopy">, and then click the </span><span class="boldbodycopy">Subscribers</span><span class="bodycopy"> tab.</span></p>
<p><span class="boldbodycopy">Code Listing 3:</span><span class="bodycopy"> StockQueueSubscriber</span></p>
<p>&nbsp;</p>
<pre>private void button2_Click_1(object sender, EventArgs e)
{
//Executes DBMS_AQADM.ALTER_SUBSCRIBER to modify the SUBSCRIBER1 subscription
string conString = &quot;User Id=hr;Password=hr;Data Source=;&quot;;
OracleConnection con = new OracleConnection();
con.ConnectionString = conString;
con.Open();

OracleCommand cmd = con.CreateCommand();

string cmdtxt = &quot;DECLARE &quot; +
    &quot;SUBSCRIBER SYS.AQ$_AGENT; &quot; +
    &quot;BEGIN &quot; +
    @&quot;SUBSCRIBER := SYS.AQ$_AGENT(&#39;&quot;&quot;SUBSCRIBER1&quot;&quot;&#39;, NULL, 0); &quot; +
    &quot;DBMS_AQADM.ALTER_SUBSCRIBER(&quot; +
    @&quot;queue_name =&gt; &#39;&quot;&quot;STOCK_Q&quot;&quot;&#39;,&quot; +
    &quot;subscriber =&gt; SUBSCRIBER,&quot; +
    &quot;rule =&gt; &#39;&quot; + textBox2.Text +&quot;&#39;,&quot; +
    &quot;transformation =&gt; &#39;&#39;&quot; +
    &quot;); &quot; +
    &quot;END;&quot;;

OracleCommandBuilder oc = new OracleCommandBuilder();
cmd.CommandText = cmdtxt;

//Execute batched statement
cmd.ExecuteNonQuery();
}
</pre>
<p><span class="bodycopy">If both of the earlier applications are still running, you should notice that your stock ticker application is now displaying only ORCL and JAVA ticker symbols. Each time the rule is modified, your running stock ticker will immediately reflect the change. </span></p>
<p><span class="bodycopy">Now go back to the Queue Subscription GUI application, click </span><span class="boldbodycopy">Clear Rule</span><span class="bodycopy">, and click </span><span class="boldbodycopy">Alter Subscription!</span><span class="bodycopy">. This will set the rule to null. Watch as the stock ticker immediately resumes displaying all the stock symbols that are loaded into the queue. </span></p>
<p><strong><span class="parahead1">Summary</span> </strong></p>
<p><span class="bodycopy">This article showed you how you can leverage Oracle Streams Advanced Queuing database-integrated messaging from .NET applications. You loaded a queue from one application, subscribed to that queue from another application, and received callback notifications based on subscription rules you modified by using the DBMS_AQADM package.</span></p>
<p><strong><span class="boldbodycopy">Christian Shay</span><span class="bodycopy"> </span></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/write-messaging-applications-with-odp-net-and-oracle-streams-advanced-queuing-119.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tips for Optimizing Rails on Oracle</title>
		<link>http://www.allfreetech.com/database/oracle-database/tips-for-optimizing-rails-on-oracle-111.html</link>
		<comments>http://www.allfreetech.com/database/oracle-database/tips-for-optimizing-rails-on-oracle-111.html#comments</comments>
		<pubDate>Tue, 16 Jun 2009 07:23:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=111</guid>
		<description><![CDATA[Using the Ruby on Rails framework it is relatively easy to develop complex systems that are backed by an Oracle database, but this ease doesn&#39;t exempt the developer from the need to optimize the data model and the code that manipulates it.&#160; This article is for developers working with Ruby on Rails applications on an [...]]]></description>
			<content:encoded><![CDATA[<p>Using the Ruby on Rails framework it is relatively easy to develop complex systems that are backed by an Oracle database, but this ease doesn&#39;t exempt the developer from the need to optimize the data model and the code that manipulates it.&nbsp;</p>
<p>This article is for developers working with Ruby on Rails applications on an Oracle database, with special attention to those having a live application that needs to be optimized. You will learn which options tweak the parameters that handle the connection to the database for the Oracle adapter to boost the application performance, as well as get a useful plugin to track down the query execution plans for live applications. You&#39;ll build a simple set of models and look at various typical queries on them, exploring how you can improve their efficiency.<span id="more-111"></span></p>
<h2>Setup</h2>
<p>The prerequisite to follow this article is having Ruby on Rails installed and configured properly to connect with an Oracle database. <a class="bodylink" href="http://www.oracle.com/technology/pub/articles/saternos-ror-faq.html">&quot;The Ruby on Rails with Oracle FAQ&quot;</a> by Casimir Saternos explains the process in detail. (It&#39;s quite easy.)</p>
<p>All the examples for this article have been written and tested on a Windows XP machine running <a class="bodylink" href="http://rubyforge.org/frs/download.php/17654/InstantRails-1.5p1-win.zip">Instant Rails 1.5 preview 1</a> connecting to <a class="bodylink" href="http://www.oracle.com/technology/products/database/xe/index.html">Oracle Database 10<em>g</em> Express Edition</a> (XE) installed on Debian Linux.</p>
<p>For the remainder of this article I will make examples based on a Rails &quot;version&quot; of the HR schema that has been modified to directly comply with the common Rail conventions (as opposed to using the standard HR schema from a Rails application, explained in Saternos&#39; <a class="bodylink" href="http://www.oracle.com/technology/pub/articles/saternos-rails.html">&quot;HR Schema On Rails&quot;</a>). This choice has been dictated by the wish to show the behavior of a standard Rails application on an Oracle database without being distracted by the specifics of handling a separate schema to map the HR schema into the Rails conventions. (Which is indeed a very clever way to handle legacy schemas!)</p>
<p>In the <a class="bodylink" href="http://www.oracle.com/technology/pub/files/mearelli-optimizing-oracle-rails-sample.zip">sample code file</a> you will find the complete migrations for the schema and a (yml format) dump of the data which can be used to load them using the Active Record fixtures plugin, which is also included. (The db/db_loading.rb file does the data import and can be executed using script/runner).</p>
<p>The six tables are populated by the very same data that the regular HR schema holds, while they have some columns modified. (E.g., all of them now use the common Rails convention of having one id column as their primary key.)</p>
<p>The models also define some relations among them; you can see the full code for the models in the sample code file:</p>
<pre>class Country &lt; ActiveRecord::Base
    belongs_to :region
    has_many  :locations
end

class Department &lt; ActiveRecord::Base
    belongs_to :manager, :class_name =&gt; &quot;Employee&quot;, :foreign_key =&gt; &quot;manager_id&quot;
    belongs_to :location
    has_many :employees
end

class Employee &lt; ActiveRecord::Base
    belongs_to :department
    belongs_to :manager, :class_name =&gt; &quot;Employee&quot;, :foreign_key =&gt; &quot;manager_id&quot;
    belongs_to :job
    belongs_to :department
    has_many :managed_employees, :class_name =&gt; &quot;Employee&quot;, :foreign_key =&gt; &quot;manager_id&quot;
end

class Job &lt; ActiveRecord::Base
  has_many :employees
end

class Location &lt; ActiveRecord::Base
  belongs_to :country
  has_many :department
end

class Region &lt; ActiveRecord::Base
	 has_many :country
end
</pre>
<p>All our tests will be done simply by connection with the Rails console and interactively querying the database through the model methods as we would do from within our controllers:</p>
<pre>
C:\Progetti\ArticoliROR\Oracle\project&gt; ruby script\console
Loading development environment.
&gt;&gt;
</pre>
<h2>Part 1: Of configuration, Cursors, and Rows</h2>
<h3>Basic Configuration</h3>
<p>So, you have already configured all the required prerequisites for running Rails on an Oracle database, and bootstrapping your Rails application is just a matter of opening a prompt window (terminal, xterm, or whatever) and typing:</p>
<pre>
rails myapp
</pre>
<p>This will reward you with a skeleton application that is ready to hold your code (models, views, controller and tests). You will need to customize the config/database.yml file telling the framework basic information for each one of the databases that Rails uses.</p>
<p>Each entry is identified with a key that tells the system if the specific information is to be used while developing the application, while running the tests or when running the application in production mode. You could even define other database connections beyond the standard three and use them from your Rails application, but this subject goes beyond the scope of this article.</p>
<p>Having separate database settings means that you may modify the values in the development or testing database and conduct your tests and measures without touching the production database.</p>
<p>Here is an example of the basic configuration:</p>
<pre>development:
  adapter: oracle
  host: DEBIAN
  username: rails
  password: rails
</pre>
<p>The adapter parameter specify that we are connecting with an Oracle database and selects the OracleAdapter (see: activerecord/lib/active_record/connection_adapters/oracle_adapter.rb ). Older Rails releases used the &#39;oci&#39; value to identify the oracle adapter, and this value can still be used.</p>
<p>With the host parameter you specify the database to which you want to connect. If you have configured TNS entry for your database:</p>
<pre>
DEBIAN =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 10.211.55.7)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = XE)
    )
  )
</pre>
<p>you may use its name for the host parameter; otherwise, you can use the Easy Connect naming convention to address the Oracle instance (host: //10.211.55.7:1521/XE).</p>
<p>The username and password are the credentials you want to use for your application. All the objects (tables, sequences) needed by the application should be accessible from this user and anything built thorough the database migrations will be built into this user&#39;s schema (at least this is the default behavior).</p>
<h3>Models and SQL Queries</h3>
<p>Now we will look at some of the queries that are generated by ActiveRecord, and this is made simple by the fact that while in development mode Rails writes all the queries it is performing to the log file. In this manner you can familiarize yourself with the behavior of the framework and gain greater confidence in what the tool will do.</p>
<p>I find that having a deeper understanding of how the framework code is going to translate your high level requests into actual SQL is a required step when working with powerful frameworks that make complex interactions with the data. You will gain a better understanding of the Rails idioms that should be used and how to write more efficient code.</p>
<p>One of the most common ways to get the model data is looking up an object by its id:</p>
<pre>emp = Employee.find(202)
</pre>
<p>will get you the employee record with id = 202. Looking at the development.log we will see the queries that are getting executed:</p>
<pre>Employee Columns (0.120000)
 select column_name as name, data_type as sql_type, data_default, nullable,
  decode(data_type, &#39;NUMBER&#39;, data_precision,
  &#39;FLOAT&#39;, data_precision,
  &#39;VARCHAR2&#39;, data_length,
 null) as limit,
 decode(data_type, &#39;NUMBER&#39;, data_scale, null) as scale
 from all_tab_columns
 where owner = &#39;RAILS&#39;
 and table_name = &#39;EMPLOYEES&#39;
 order by column_id

Employee Load (0.070000)  SELECT * FROM employees WHERE (employees.id = 202)
</pre>
<p>The first query is executed once the first time a model class is loaded to pull the columns from the employee table allowing the system to dynamically generate the required methods for the model based on the database structure. (This is one of those features that make Rails development really quick!) Be warned that while doing your activity and running the server in development mode you will see this query repeated many times as the models get reloaded on each browser request. This makes the server slower but allows you to get the updates to the database structures without restarting the server.</p>
<p>The second query gets the data from the employees table for the employee whose id is 202.</p>
<p>Other examples of the models may be the following (all presented with the actual query executed on the database):</p>
<p><em>Given an employee, get its department manager.</em></p>
<pre>mgr = emp.department.manager

SELECT * FROM departments WHERE (departments.id = 20)
SELECT * FROM employees WHERE (employees.id = 201)
</pre>
<p><em>Given an employee, get all the colleagues at the same department.</em></p>
<pre>emps = emp.department.employees

SELECT * FROM employees WHERE (employees.department_id = 20) 

mgr.managed_employees

SELECT * FROM employees WHERE (employees.manager_id = 201) </pre>
<p>You may use the include option to pull down in a single query from the server also objects which have some relation with our entity:</p>
<pre>emp = Employee.find(202, :include=&gt;[:department,:manager])
emp.department
emp.manager

SELECT employees.id AS t0_r0, employees.commission AS t0_r1, employees.job_id AS t0_r2,
employees.manager_id AS t0_r3,employees.salary AS t0_r4, employees.hire_date AS t0_r5,
employees.phone_number AS t0_r6, employees.department_id AS t0_r7,
employees.first_name AS t0_r8, employees.last_name AS t0_r9, employees.email AS t0_r10,
departments.id AS t1_r0, departments.name AS t1_r1, departments.manager_id AS t1_r2,
departments.location_id AS t1_r3, managers_employees.id AS t2_r0,
managers_employees.commission AS t2_r1, managers_employees.job_id AS t2_r2,
managers_employees.manager_id AS t2_r3, managers_employees.salary AS t2_r4,
managers_employees.hire_date AS t2_r5, managers_employees.phone_number AS t2_r6,
managers_employees.department_id AS t2_r7, managers_employees.first_name AS t2_r8,
managers_employees.last_name AS t2_r9,
managers_employees.email AS t2_r10 FROM employees LEFT OUTER JOIN departments
  ON departments.id = employees.department_id LEFT OUTER JOIN employees managers_employees
  ON managers_employees.id = employees.manager_id WHERE (employees.id = 202)
</pre>
<p>This is really handy and efficient when working with objects behaving as containers for sets of other items as it avoids going to the database with a query for each and every row you want to manipulate.</p>
<p>Here&#39;s another example:</p>
<pre>job = Job.find(id,:include=&gt;:employees)
job.employees

SELECT jobs.id AS t0_r0, jobs.job_title AS t0_r1, jobs.min_salary AS t0_r2,
jobs.max_salary AS t0_r3, employees.id AS t1_r0, employees.commission AS t1_r1,
employees.job_id AS t1_r2, employees.manager_id AS t1_r3, employees.salary AS t1_r4,
employees.hire_date AS t1_r5, employees.phone_number AS t1_r6,
employees.department_id AS t1_r7, employees.first_name AS t1_r8,
employees.last_name AS t1_r9, employees.email AS t1_r10 FROM jobs LEFT OUTER JOIN employees
  ON employees.job_id = jobs.id WHERE (jobs.id = 7)
</pre>
<p>One of the points of this article is to show you the new configuration parameters introduced with the release 1.2 of Rails that may help in tuning the database-related performance of your application, but before going deeper into it let me explain how currently Rails builds the actual SQL used.</p>
<h3>Bind Variables and Cursor Sharing</h3>
<p>ActiveRecord uses its (dynamically built) knowledge of the models and database to create queries on the fly. It even builds many methods of the models themselves in this way allowing the developer to write things like:</p>
<pre>Employee.find_by_first_name_and_last_name(&#39;Steven&#39;,&#39;King&#39;)
</pre>
<p>but it does so by building the SQL query as a string and doing parameter interpolation before sending the query to the adapter for execution (without using bind variables). SQL injection and security problems are attacked at the adapter level by quoting the values on SQL interpolation but the performance hit remains, and it also impacts the scalability of any Rails application running on Oracle. To understand how this impacts performance and scalability, let me explain what happens when a query is executed.</p>
<p>When a query is first executed Oracle performs a hard parse step which verifies that it is syntactically correct and that all the objects (tables, columns, &#8230;) being accessed really exist. If the checks pass, a new entry is created in the library cache with the parse results that may be reused for subsequent executions. The key to the library cache is the SQL text for the query itself, therefore two queries that have any literal difference are considered different for the purposes of parsing.</p>
<p>When a new query is executed, a hash lookup into the library cache is done to see if the query had been already parsed. If the query is found then the cached parse result is used and the hard parse step is avoided, moreover no new entries are added to the library cache. A way to minimize hard parses is to always use bind parameters.</p>
<p>Within the context of a pre-1.2 Rails application, without any specific database tuning this means that each time a different query is executed (even if it differs just for the parameter values), the statement is hard parsed by the database engine and a new query entry is inserted in the library cache.</p>
<p>You can verify what happens by looking at the v$sql view where the sql_text column holds the actual SQL used for the queries: each row in v$sql corresponds to an entry in the library cache. We may use the following query to get all the queries generated by our application (limiting ourselves to the queries that hit one of the 6 tables):</p>
<pre>select sql_text from v$sql
where (    lower(sql_text) like &#39;%employee%&#39;
        or lower(sql_text) like &#39;%countries%&#39;
        or lower(sql_text) like &#39;%departments%&#39;
        or lower(sql_text) like &#39;%jobs%&#39;
        or lower(sql_text) like &#39;%locations%&#39;
        or lower(sql_text) like &#39;%regions%&#39;
      )
and   not lower(sql_text) like &#39;%v$sql%&#39;
order by sql_text
If we do the following:
(1..200).each do |id|
	Employee.find(id) rescue nil
end
</pre>
<p>which tries to get each Employee with id between 1 and 200. You&#39;d end up with the following in v$sql:</p>
<pre>SQL_TEXT
--------------------------------------------------------------------------------
SELECT * FROM employees WHERE (employees.id = 1)
SELECT * FROM employees WHERE (employees.id = 10)
SELECT * FROM employees WHERE (employees.id = 100)
SELECT * FROM employees WHERE (employees.id = 101)
...
</pre>
<p>This is not an advisable behavior from an application expected to scale, especially for the common patterns of use where you may expect many queries using the primary key (e.g. accessing to the user table for login purposes or for configuration data).</p>
<p>Work is under way to provide Rails with proper handling of bind variables, or at least to let ActiveRecord adapters themselves do the binding of parameters within the query. In the meantime the best option is to use the ability to handle query rewriting built into the database.</p>
<p>A specific configuration offered by Oracle comes to the rescue here. The CURSOR_SHARING database parameter changes the way the database behaves doing hard and soft parses in presence of queries that are not using bind parameters. The parameter can be set to <em>exact</em>, <em>similar</em>, or <em>force</em> (and the latter can be set databasewide or on a specific session).</p>
<ul type="square">
<li><em>exact</em> is the default value where the database behaves as outlined above.</li>
<li><em>force</em> tells the database to rewrite all the queries substituting the literals in the SQL text with bind parameters (e.g. :&quot;SYS_B_0&quot;) resulting in one parsed entry for each query.</li>
<li><em>similar</em> rewrites the query but also looks at the effect of such rewrite and generates different entries in library cache for queries that would end up using different execution plans&mdash;that is, if substituting the literal with a bind parameter would end up in a different plan being executed then the replacement is not done.</li>
</ul>
<p>Before Rails 1.2, to change the cursor sharing setting you&#39;d need to change it for the entire database instance or patch the ActiveRecord adapter. From the last major release an adapter configuration parameter has been added to do just that.</p>
<p>The cursor_sharing setting can be used in database.yml to choose the preferred value without messing with the global database parameters (thus being better citizens in an heterogeneous environment where other applications may require different settings).</p>
<pre>development:
  adapter: oracle
  host: DEBIAN
  username: rails
  password: rails
  cursor_sharing: similar
</pre>
<p>Its value is used straight in an alter session statement upon establishing a connection (in OracleConnectionFactory.new_connection):</p>
<pre>conn.exec &quot;alter session set cursor_sharing = #{cursor_sharing}&quot; rescue nil
</pre>
<p>Moreover the default value has been chosen to be <em>similar</em>, which means that without needing to add cursor_sharing to the parameters you get a reasonable behavior: the queries are changed according to the plan that would be used depending on the values.</p>
<p>If you redo the query above you&#39;ll see this in v$sql:</p>
<pre>SELECT * FROM employees WHERE (employees.id = :&quot;SYS_B_0&quot;)
just one library cache entry for any Employee.find(id) call.
</pre>
<p>To see the impact of <em>similar</em> vs. <em><em>force</em></em>, update the table to have some skewed data:</p>
<pre>Employee.find(:all).each do |emp|
	emp.salary = 3000 unless emp.id == 100
	emp.save
end
</pre>
<p>You updated all the records to have a salary of 3,000 except for the one whose id equals 100. Now you can add an index to the employee table from within the Rails project by generating a migration:</p>
<pre>C:\Progetti\ArticoliROR\Oracle\project&gt;ruby script/generate migration AddIndexes
      exists  db/migrate
      create  db/migrate/007_add_indexes.rb
</pre>
<p>In the generated file you should have</p>
<pre>class AddIndexes &lt; ActiveRecord::Migration
  def self.up
    add_index :employees, :salary, :name=&gt;:idx_emp_salary
   end

  def self.down
    remove_index :employees, :name=&gt;:idx_emp_salary
  end
end
then we do a rake db:migrate from the command line. Now if we do:
Employee.find(:all, :conditions=&gt;[&quot;salary = ?&quot;, 24000])
Employee.find(:all, :conditions=&gt;[&quot;salary = ?&quot;, 3000])
</pre>
<p>You&#39;ll find two parsed entries in v$sql:</p>
<pre>SELECT * FROM employees WHERE (salary = :&quot;SYS_B_0&quot;)
SELECT * FROM employees WHERE (salary = :&quot;SYS_B_0&quot;)
</pre>
<p>This is because the two queries generated would use two different plans depending on the salary value. (In the first case the index would be used while in the second case a full table scan would result being the best plan.) Using force cursor sharing would tell the database to use to the same parsed entry for both queries which is not what we want in this case, even if it meant having only one cache entry.</p>
<p>Having a configuration available for this from Rails, let&#39;s tune its value on a per-application case, depending also on which kind of data you have and on which patterns of use you are seeing for your application.</p>
<p>A second parameter added to Rails 1.2, which may help in tuning the application, is the prefetch_rows configuration. This allows setting the OCI_ATTR_PREFETCH_ROWS connection parameter, which specifies the amount of rows to be pre-fetched from the database on each round trip. It can give a great performance boost in all cases where you want to fetch many rows.</p>
<p>Typical patterns are iterations over a set of entities like in:</p>
<pre>Employee.find(:all, :conditions=&gt;&quot;salary &lt; 5000&quot;)
</pre>
<p>In these cases rows pre-fetching means fewer hits to the database, while the cost is more memory used by the adapter&mdash;which is not a problem anyway if you want to process all the rows returned by the query.</p>
<p>The default value is set to 100 which has been identified by the Oracle adapter contributors to be ideal in a range of test cases, but more than for cursor_sharing the prefetch value needs to be tweaked by benchmarking with the real data-sets and queries used in the application. For custom tuning this parameter is set in database.yml as usual:</p>
<pre>development:
  adapter: oracle
  host: DEBIAN
  username: rails
  password: rails
  prefetch_rows: 100
  </pre>
<h2>Part 2: Execution plans and Indexes</h2>
<h3>What Rails Cannot Do</h3>
<p>While Rails goes great lengths toward reducing the burden of development through a clever use of conventions and design pattern implementation, there are situations where it cannot have the required knowledge to make the decisions for the developer. Thus, the Rails developer should not forget that he or she is building a database-backed application, nor which database he or she is developing for.</p>
<p>While most of the coding is doable in a fairly database independent way a good understanding of how a database works is required if you want to get the best performance out of your applications.</p>
<p>Knowing how your database works is useful while developing the data model and while building the queries, but it is much more important when deciding which indexes you need on your tables. This is something that the framework cannot do and does not even attempt to do, as it would depend on:</p>
<ul type="square">
<li>the specific database that is used (as it might have or not have some capability when it comes to creating and using indexes)</li>
<li>the data that is present in the tables (as they influence the query execution plan and which indexes are used)</li>
<li>the specific application (as the actual queries used may access the data in unpredictable ways based on usage patterns)</li>
</ul>
<p>Moreover these factors influence each other and any optimization will depend on all of them collectively. In his blog post <a class="bodylink" href="http://weblog.jamisbuck.org/2006/10/23/indexing-for-db-performance">&quot;Indexing for DB Performance&quot;</a>, Jamis Buck gives some tips on the kind of indexes that might be needed:</p>
<ul type="square">
<li>foreign keys (has_one, belongs_to, has_many, &#8230; relations)</li>
<li>non-index fields that are frequently queried upon (e.g. login names)</li>
<li>columns where you sort of do calculations frequently</li>
<li>sets of columns that are used as conditions together</li>
</ul>
<p>Each index adds some overhead as it needs to be updated on data insert and update, so you should not add indexes for every column (or combination of them). Rather you should make informed choices starting with some reasonable set of indexes, modifying them as the application evolves over time, taking into account the actual data and usage patterns.</p>
<p><strong>Explain Plan. </strong>In an Oracle context, this means using the <tt>explain plan</tt> command to understand how queries are executed. It gives the developer a way to optimize the query itself and to eventually add indexes.</p>
<p>You should always try to optimize the query first and only afterward go on to add the indexes.</p>
<p>Rails makes it rather easy to use custom queries instead of a regular one with the handy find_by_sql method of ActiveRecord. Note however that in the find_by_sql call you could simply pass the text of the SQL query, but you should really confirm that you use the parameter substitution form, passing an array with the query and the list of parameters. This way you can use the parameter quoting that is in the database adapter and you make sure that you will use real bind variables in future when ActiveRecord supports them without the need to modify your code.</p>
<p><strong>Query_Analyzer Plugin.</strong> While looking for bottlenecks in your application it is important that you get to know which queries are executed. The Rails log files can be really useful here, as the application while running in development mode logs all the actual queries. They might be collected and examined one by one to find the queries and generate the execution plans. This can become tedious work. The query_analyzer plugin helps relieve the burden by dumping the explain plan output in the log file. You can get an Oracle compatible release <a class="bodylink" href="http://www.spazidigitali.com/wp-content/uploads/2006/12/query_analyzer.zip">here</a>; it was originally developed by Bob Silva for MySQL. To install it just unzip the archive contents in the vendor/plugins directory on your Rails project.</p>
<p>To allow the plugin to work in Oracle the database user will need to be given enough privileges on the data dictionary tables that are queried on loading the model. The following statement will do it:</p>
<pre>GRANT SELECT ANY DICTIONARY TO &lt; database user &gt;;
</pre>
<p>The plugin monkey patches the database adapter to add the explain plan for each query that is executed by the adapter while running at a logging level below INFO. The plan is formatted and printed at the debug level to the default logger. This default behavior makes sure that the plan is not executed while running on the production environment.</p>
<p>Two parameters are available to modify the default behavior; both can be modified within the environment setup files: The plan_table_name parameter can be used to specify the name of the plan table and its default is the standard PLAN_TABLE; the plan_details parameter can be used to specify which details should be printed by the explain plan statement. Possible values are:</p>
<ul type="square">
<li>BASIC: displays minimum information</li>
<li>TYPICAL: displays most relevant information (default value)</li>
<li>SERIAL: like TYPICAL but without parallel information</li>
<li>ALL: displays all information</li>
</ul>
<p>If you execute a common query:</p>
<pre>Employee.find(101)
</pre>
<p>it will dump the following data to the development.log file:</p>
<pre>
Employee Load (0.000000)  explain plan for SELECT * FROM employees WHERE (employees.id = 101)
Analyzing Employee Load
  plan_table_output
   -------------------------------------------------------------------------------------------
   Plan hash value: 1171009080                                                                

   -------------------------------------------------------------------------------------------
   | Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
   -------------------------------------------------------------------------------------------
   |   0 | SELECT STATEMENT            |             |     1 |   719 |     2   (0)| 00:00:01 |
   |   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES   |     1 |   719 |     2   (0)| 00:00:01 |
   |*  2 |   INDEX UNIQUE SCAN         | SYS_C004026 |     1 |       |     1   (0)| 00:00:01 |
   -------------------------------------------------------------------------------------------

   Predicate Information (identified by operation id):
   ---------------------------------------------------                                        

      2 - access(&quot;EMPLOYEES&quot;.&quot;ID&quot;=101)
</pre>
<p>Note that the query uses a unique index related to the primary key for the table; in this case, nothing needs to be done.</p>
<p>Leaving the plugin active (setting a debug level of informations) allows you to collect the plan table outputs for all queries while running the application.</p>
<p>The plan table outputs a lot of information on the queries. You can quickly spot the tables that may need a new index by searching for &#39;TABLE ACCESS FULL&#39; in the log file.</p>
<pre>
Employee Load (0.010000)  explain plan for SELECT * FROM employees WHERE (first_name = &#39;Stephen&#39;)
Analyzing Employee Load
  plan_table_output
   -------------------------------------------------------------------------------
   Plan hash value: 1445457117                                                    

   -------------------------------------------------------------------------------
   | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
   -------------------------------------------------------------------------------
   |   0 | SELECT STATEMENT  |           |     1 |   719 |     3   (0)| 00:00:01 |
   |*  1 |  TABLE ACCESS FULL| EMPLOYEES |     1 |   719 |     3   (0)| 00:00:01 |
   -------------------------------------------------------------------------------

   Predicate Information (identified by operation id):
   ---------------------------------------------------                            

      1 - filter(&quot;FIRST_NAME&quot;=&#39;Stephen&#39;)                                          

   Note
   -----
      - dynamic sampling used for this statement
</pre>
<p>This is the result of querying all the employees that have first name &#39;Stephen&#39;: Employee.find(:all, :conditions=&gt;[&quot;first_name = ?&quot;, &quot;Stephen&quot;]).</p>
<p>Note that this query needs to scan the full EMPLOYEES table to get just one row when using a filter on the first_name column. If this kind of query is seen many times through the application, you should consider adding an index. The predicate information for the more costly operations gives you a good hint at what indexes may benefit the query execution&mdash;in this case, obviously an index on the first_name column.</p>
<p><strong>Rails Migrations.</strong> You can also use Rails Migrations to manage indexes. (See the API docs for more information on what Migrations are and how to use them to manage a database schema.) To add an index use:</p>
<pre>add_index table_name, column_names, options = {}
</pre>
<p>this adds an index on &quot;table_name&quot; for &quot;column_names&quot; where the latter can be a single column or a list of columns:</p>
<pre>add_index :departments, :manager_id
add_index :locations, [:city, :postal_code]
</pre>
<p>Within the options parameter you can specify if the index is to be created as unique:</p>
<pre>add_index :locations, [:city, :postal_code, :street_address], :unique =&gt; true
</pre>
<p>or with a given name. (This is useful on Oracle since the default is to use a combination of table name and first column name, which can be too long.)</p>
<pre>add_index :locations, [:city, :postal_code], :name =&gt; :idx_city_zip
</pre>
<p>To remove an index just use the remove_index method:</p>
<pre>remove_index table_name, options = {}
we can pass as options the column name(s) or the index name:
  remove_index :departments, :manager_id
  remove_index :departments, :column =&gt; :manager_id
  remove_index :locations, :column =&gt; [:city, :postal_code, :street_address]
  remove_index :locations, :name =&gt; :idx_city_zip
</pre>
<p>If you need to use more complex or database-specific SQL, use the <tt>execute</tt> command from the up or down methods to which you pass the SQL string to execute:</p>
<pre>execute &quot;CREATE INDEX idx_emp_first_name ON employees (first_name)&quot;
</pre>
<p>In the example above:</p>
<pre>C:\Progetti\ArticoliROR\Oracle\project&gt;ruby script/generate migration AddFirstNameIndex
      exists  db/migrate
      create  db/migrate/008_add_first_name_index.rb
</pre>
<pre>This is the migration file:</pre>
<pre>class AddFirstNameIndex &lt; ActiveRecord::Migration
  def self.up
    add_index :employees, :first_name, :name=&gt;:idx_emp_first_name
   end

  def self.down
    remove_index :employees, :name=&gt;:idx_emp_first_names
  end
end
</pre>
<p>Run the migration using rake db:migrate.</p>
<pre>C:\Progetti\ArticoliROR\Oracle\project&gt;rake db:migrate
(in C:/Progetti/ArticoliROR/Oracle/project)
== AddFirstNameIndex: migrating ===============================================
-- add_index(:employees, :first_name, {:name=&gt;:idx_emp_first_name})
   -&gt; 0.0100s
== AddFirstNameIndex: migrated (0.0100s) ======================================
</pre>
<p>Executing the query again shows that the index is now used:</p>
<pre>
Employee Load (0.010000)  explain plan for SELECT * FROM employees WHERE (first_name = &#39;Stephen&#39;)
Analyzing Employee Load
  plan_table_output
   --------------------------------------------------------------------------------------------------
   Plan hash value: 2736374945                                                                       

   --------------------------------------------------------------------------------------------------
   | Id  | Operation                   | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
   --------------------------------------------------------------------------------------------------
   |   0 | SELECT STATEMENT            |                    |     1 |   719 |     2   (0)| 00:00:01 |
   |   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES          |     1 |   719 |     2   (0)| 00:00:01 |
   |*  2 |   INDEX RANGE SCAN          | IDX_EMP_FIRST_NAME |     1 |       |     1   (0)| 00:00:01 |
   --------------------------------------------------------------------------------------------------

   Predicate Information (identified by operation id):
   ---------------------------------------------------                                               

      2 - access(&quot;FIRST_NAME&quot;=&#39;Stephen&#39;)                                                             

   Note
   -----
      - dynamic sampling used for this statement
</pre>
<p>As you have seen it is really easy to use the plugin to poke at the execution plans used by a running application and you may even leave it installed on the production server and disable/enable it when needed by changing the logging level.</p>
<h2>Conclusion</h2>
<p>In this article you dug a bit into how connections to an Oracle database are configured in a Rails application, and you have seen how the framework has been updated in the 1.2 release to have better performances thorough the use of the cursor_sharing and prefetch_rows parameters (while waiting for a real bind variable implementation).</p>
<p>You have also examined the Rails migration commands that are relevant to tuning the database (specially creating/removing indexes).</p>
<p>Finally, as you&#39;ve learned, a good understanding of both how Rails builds the SQL from the code and how the database executes them is needed to get the best performance. The provided plugins should help here. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/database/oracle-database/tips-for-optimizing-rails-on-oracle-111.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

