Having migrated many systems from SQL Server to Oracle, I used to want to cry when I encounter this type of construct.
CREATE PROCEDURE GetLoadsOfData AS BEGIN SELECT t1.name salutation FROM salutation t1; -- Salutations, Mr, Mrs, ... SELECT t1.name skill FROM technicalSkill t1; -- Oracle, C#, XSLT, ... SELECT t1.name AS countryName, -- Countries and currency codes t2.code AS currencyCode FROM countryCurrency t3 INNER JOIN country t1 ON t1.id = t3.countryID INNER JOIN currency t2 ON t2.id = t3.currencyID END
To state the blindingly obvious, this piece of innocuous looking T-SQL
Developers can rarely defend this type of construct, over for example three different methods named GetSalutations, GetCountries, and GetCurrencies (and ask yourself, isn’t the purpose of each if these methods clear when discretely named like this?), other than reducing the ‘chatter’ in a n-tier application for retrieving lookup data. Put another way, with a single database method, there is a minimal number of database procedures, and some application data layer/middleware can initialise itself with only one invocation, not multiple invocations, loads of interprocess communication, and concerns with lazy or other types of loading and synchronisation of all the API method calls.
Despite the SQL Server DBMS not providing direct functionality to consume procedures that return multiple result-sets, the Microsoft technology stack (and third-party) appear to have no interoperability issues with consuming the result sets. For example, C# using Dapper (I’ve chosen Dapper as I doubt you can get a more cut-down ORM meaning I can minimally demonstrate consumption of multiple result-sets), as shown below, shows basic ORM without digressing into other and more complex object relational mapping technologies such Entity Framework, ADO.NET, or flavours of Hibernate.
using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using Dapper; namespace ConsoleApplication3787 { public class Country { public String CountryName { get; set; } public String CurrencyCode { get; set; } //other properties/omitted } class Program { public List<Country> Countries { get; set; } public List<String> Salutations { get; set; } public List<String> TechnicalSkill { get; set; } public void Setup() //setup/initialise application lookup data { using (IDbConnection db = new SqlConnection(@"Server=MACBOOK003\SQLEXPRESS;Trusted_Connection=true;Initial Catalog=DEV")) { db.Open(); var multipleResultSets = db.QueryMultiple(sql: "GetLoadsOfData", commandType: CommandType.StoredProcedure); Salutations = multipleResultSets.Read<String>().ToList(); TechnicalSkill = multipleResultSets.Read<String>().ToList(); Countries = multipleResultSets.Read<Country>().ToList(); db.Close(); } } static void Main(string[] args) { var app = new Program(); app.Setup(); //other stuff } } }
I am migrating the codebase
from:
Microsoft SQL Server 2005 – 9.00.3042.00 (Intel X86) Feb 9 2007 22:47:07 Copyright (c) 1988-2005 Microsoft Corporation Express Edition on Windows NT 6.1 (Build 7601: Service Pack 1)
to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 – 64bit Production
that were released in 2005 and 2007 respectively. The other technologies are C# and Dapper.
Now, back to the subject of SQL Server to Oracle migration. Given that during the database migration in my current project, there is little wiggle room to justify system architecture changes, or considerable changes to the API (that would involve pervasive middleware changes and knock-on changes to dependent components and unit tests) , the question is now how to return multiple result-sets returned in Oracle.
The answer is to use DBMS_SQL.RETURN_RESULT, that requires an incredible amount of code bloat to coerce Oracle into doing something that SQL Server has been able to do since at least 2005. Unfortunately, DBMS_SQL.RETURN_RESULT is only available from Oracle version 12c, the most recent version of the Oracle database, and not my target version (as at March 2017, the most recent version of Oracle Express Edition is still 11g]).
Oh dear – weeks more of refactoring because the Oracle feature set is behind competitors. Guru Steven Feuerstein makes a comment on this issue too. For me however, just this once, I would have preferred Oracle had not implemented ‘procedures’ that return multiple result-sets. This isn’t because of all the additional Oracle codebase bloat (compared to SQL Server – see Feuerstein’s code examples and my SQL Server example above) that seem to accompany most Oracle retrofitted functionality, but because constructs like GetLoadsOfData, rather than discrete clearly named self describing API methods that return one type of data, just have to be the model for producing maintainable code.
Although I regularly experience the ‘Why does/doesn’t Oracle do this’ déjà vu, especially in database migration projects, should 12c Express Edition become available, I will not voluntarily adopt the model of writing an API that returns some complex structured object even though DBMS_SQL.RETURN_RESULT would be available to me. Database PSM methods that return one thing and as described by the PSM method name are ……. well, do I need to write anything at all here, this blog article should be a lot smaller, as it’s all just about common sense programming isn’t it?
— Published by Mike, 10:23 20 March 2017
By Month: November 2022, October 2022, August 2022, February 2021, January 2021, December 2020, November 2020, March 2019, September 2018, June 2018, May 2018, April 2018
Apple, C#, Databases, Faircom, General IT Rant, German, Informatics, LINQ, MongoDB, Oracle, Perl, PostgreSQL, SQL, SQL Server, Unit Testing, XML/XSLT
Leave a Reply