项目作者: ClayLipscomb

项目描述 :
C# code generator for Oracle packages
高级语言: C#
项目地址: git://github.com/ClayLipscomb/Odapter.git
创建时间: 2018-02-21T22:56:47Z
项目社区:https://github.com/ClayLipscomb/Odapter

开源协议:GNU General Public License v3.0

下载


Odapter - a C# code generator for Oracle packages

Odapter is a single-file desktop application that generates C# adapter classes to provide integration with Oracle packages. An adapter class handles the invocation of a package’s procedures and the hydration of interface-implementing DTO collections from returned cursor results sets, both typed (record based) and untyped (simple REF CURSOR). From within the IDE, the generated code provides the .NET developer de facto compile-time resolution with the packages. Optionally, standalone C# DTOs (class or record) can be generated from Oracle objects, tables and views.

Minimum System Requirements

  • Oracle RDBMS 11g
  • Windows 64-bit
  • .NET Versions
    • Generator application: .NET 4.6.2 minimum
    • Destination project: .NET 4.0 (minimum) or .NET 5.0 (minimum)
  • ODP.NET for destination project
    • .NET 4.x: Managed Driver 12.2.x
    • .NET 5.0+: Managed Driver Core 3.2.x

Oracle to C# Translation Examples

PL/SQL and Schema Objects C#
Case insensitive Case sensitive
snake_case naming PascalCase & camelCase naming
Package Record Field Property
Package Record Interface of properties (mutable or immutable)
Function or Stored Procedure (packaged) Method
Package Singleton class of methods and interfaces
Schema Namespace (with nesting)
Object, Table, View Interface of properties (mutable or immutable)

Code Generation Features

  • Generates adapter class for each package with respective method for each procedure/function
  • Generates nested interface for each package record as either:
    • mutable class
    • immutable record, including positional style with parameterless constructor (C# 9.0 only)
  • Translates all common Oracle data types to C#
  • Configurable translation of Oracle REF CURSROR (typed and untyped) to IList, ICollection, or List
  • Configurable translation of Oracle integer-indexed associative array type to IList or List of value type
  • Configurable translation of Oracle INTEGER, NUMBER, DATE, TIMESTAMP types, including options for ODP.NET safe types (OracleDecimal, OracleDate, OracleTimestamp)
  • Configurable translation of Oracle BLOB and CLOB/NCLOB types, including options for ODP.NET safe types (OracleBlob, OracleClob)
  • Translates Oracle IN, OUT and IN OUT parameters to C#
  • Translates Oracle optional (defaulted) parameters to C#
  • Generates interface for each object, table, and view as either:
    • mutable class
    • immutable record, including positional style with parameterless constructor (C# 9.0 only)
  • Generates ancestor adapter class for customization
  • Generates default database connection logic for customization
  • Configurable C# namespaces, ancestor class names and file names
  • Generates post hook for profiling a package procedure invoked from C#
  • Optionally filters schema objects via prefix and/or special characters
  • Optionally generates C# package adapter classes as partial
  • Generates C# 4.0 compatible code (.NET 4.0+) or C# 9.0 compatible code (.NET 5+)
  • Generates single C# file for all packages, objects, tables and views, respectively
  • Handles package referencing a record defined in a different package (including filtered)
  • Easily adaptable to legacy .NET projects and Oracle schemas
  • Locates and parses local TNSNAMES.ORA for Oracle instances
  • Persists code generation settings to config file for handling multiple projects/schemas

Run Time Features - Packages

  • Invokes packaged functions and stored procedures
  • Hydrates a List of (package record derived) DTOs from a returned (incl. OUT param) typed cursor result set
  • Hydrates a List of DTOs from a returned untyped cursor result set using configurable mapping:
    • Mapping by name: column name to property name (snake_case column translated to public PascalCase property, or protected camelCase field or private underscore-prefixed camelCase field)
    • Mapping by position: column position to property position via HydratorMapAttribute attribute
    • For performance, uses thread-safe static cache for mappings of C# DTO to Oracle result set
  • Constructs (from underlying columns) and hydrates DataTable from returned untyped cursor result set; captions are generated from column name or alias
  • Optionally limits the number of rows returned from any cursor result set

Getting Started: Generating Code for Packages

  1. Download Odapter.exe from OdapterWnFrm/bin/Release and run
  2. If Oracle Client Homes are found, select appropriate value
  3. Select Instance (If TNSNAMES.ORA file is not found/parsed in Step 2, Instance can be entered)
  4. Enter Schema, Login and Password
  5. If the destination project uses only a prefixed subset of the schema’s packages, enter Filter Prefix value
  6. Enter the Output Path for all generated files (destination project folder)
  7. Select either 4.0 or 9.0 for C# Version Generated
  8. For all other fields, use default settings
  9. Click Generate
  10. After successful generation, enter a project based .config file name in File Source and click Save Current
  11. Open the destination project and add the generated files
  12. Install the managed ODP.NET driver, OracleManagedDataAccess 12.2.x for C# 4.0 and OracleManagedDataAccess.Core 3.2.x for C# 9.0.
  13. Add “using Schema.YourSchemaName.YourFilterPrefixIfAny.Package” to destination project files in order to access packages

For examples, see code below, Tester.cs and Tester.NET5.cs.

Code Example

Package Specification - Tester/schema/package/xmpl_pkg_example.pks
  1. CREATE OR REPLACE PACKAGE ODPT.xmpl_pkg_example AS
  2. -- assoc array of integers
  3. TYPE t_assocarray_integer IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
  4. -- typed cursor
  5. TYPE t_table_big_partial IS RECORD (
  6. id odpt_table_big.id%TYPE, -- NUMBER
  7. col_integer odpt_table_big.col_integer%TYPE, -- INTEGER
  8. col_number odpt_table_big.col_number%TYPE, -- NUMBER
  9. col_varchar2_max odpt_table_big.col_varchar2_max%TYPE, -- VARCHAR2(4000)
  10. col_date odpt_table_big.col_date%TYPE, -- DATE
  11. col_timestamp odpt_table_big.col_timestamp%TYPE); -- TIMESTAMP
  12. TYPE t_ref_cursor_table_big_partial IS REF CURSOR RETURN t_table_big_partial;
  13. -- untyped cursor
  14. TYPE t_ref_cursor IS REF CURSOR;
  15. FUNCTION get_rows_typed_ret (p_in_number IN NUMBER, p_in_out_varchar2 IN OUT VARCHAR2, p_in_out_assocarray_integer IN OUT t_assocarray_integer,
  16. p_out_date OUT DATE) RETURN t_ref_cursor_table_big_partial;
  17. FUNCTION get_rows_untyped_ret (p_in_integer IN INTEGER) RETURN t_ref_cursor;
  18. END xmpl_pkg_example;
  19. /
Package Body - Tester/schema/package/xmpl_pkg_example.pkb
  1. CREATE OR REPLACE PACKAGE BODY ODPT.xmpl_pkg_example AS
  2. FUNCTION get_rows_typed_ret (p_in_number IN NUMBER, p_in_out_varchar2 IN OUT VARCHAR2, p_in_out_assocarray_integer IN OUT t_assocarray_integer,
  3. p_out_date OUT DATE) RETURN t_ref_cursor_table_big_partial IS
  4. l_cursor t_ref_cursor_table_big_partial;
  5. l_idx INTEGER;
  6. BEGIN
  7. OPEN l_cursor FOR
  8. SELECT id, col_integer, col_number, col_varchar2_max, col_date, col_timestamp
  9. FROM odpt_table_big
  10. ORDER BY id;
  11. -- multiply each value in assoc array by 7 before returning
  12. l_idx := p_in_out_assocarray_integer.FIRST;
  13. WHILE l_idx IS NOT NULL LOOP
  14. p_in_out_assocarray_integer(l_idx) := p_in_out_assocarray_integer(l_idx) * 7;
  15. l_idx := p_in_out_assocarray_integer.NEXT(l_idx);
  16. END LOOP;
  17. p_in_out_varchar2 := 'Goodbye';
  18. p_out_date := TO_DATE ('31-DEC-1999');
  19. RETURN l_cursor;
  20. END;
  21. FUNCTION get_rows_untyped_ret (p_in_integer IN INTEGER) RETURN t_ref_cursor IS
  22. l_cursor t_ref_cursor;
  23. BEGIN
  24. OPEN l_cursor FOR -- dynamic SQL, result set is dynamically typed
  25. 'SELECT id, col_integer, col_number,
  26. col_varchar2_max varchar2_max_col /* use alias to test DataTable caption */,
  27. col_date, col_timestamp
  28. FROM odpt_table_big
  29. ORDER BY id';
  30. RETURN l_cursor;
  31. END;
  32. END xmpl_pkg_example;
  33. /
Generation for C# 4.0

Generated C# 4.0 Code - Example/generated/OdptXmplPackage.cs
  1. //------------------------------------------------------------------------------
  2. // <auto-generated>
  3. // This code was auto-generated by Odapter 2.01 on Tue, 08 Jun 2021 20:19:04 GMT.
  4. // Direct edits will be lost if the code is regenerated.
  5. // </auto-generated>
  6. //------------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Data;
  10. using System.Data.Common;
  11. using Oracle.ManagedDataAccess.Client;
  12. using Oracle.ManagedDataAccess.Types;
  13. using System.Collections;
  14. using System.Diagnostics;
  15. using System.Runtime.Serialization;
  16. using System.Xml;
  17. using System.Xml.Serialization;
  18. using System.Linq;
  19. using Odapter;
  20. namespace Schema.Odpt.Xmpl.Package {
  21. public sealed partial class XmplPkgExample : Schema.Odpt.Xmpl.OdptAdapter {
  22. private XmplPkgExample() { }
  23. private static readonly XmplPkgExample _instance = new XmplPkgExample();
  24. public static XmplPkgExample Instance { get { return _instance; } }
  25. public interface ITTableBigPartial {
  26. Int64? Id { set; }
  27. Int64? ColInteger { set; }
  28. Decimal? ColNumber { set; }
  29. String ColVarchar2Max { set; }
  30. DateTime? ColDate { set; }
  31. OracleTimeStamp? ColTimestamp { set; }
  32. } // ITTableBigPartial
  33. public IList<TypeITTableBigPartial> ReadResultITTableBigPartial<TypeITTableBigPartial>(OracleDataReader rdr, UInt32? optionalMaxNumberRowsToReadFromAnyCursor = null)
  34. where TypeITTableBigPartial : class, ITTableBigPartial, new() {
  35. IList<TypeITTableBigPartial> __ret = new List<TypeITTableBigPartial>();
  36. if (rdr != null && rdr.HasRows) {
  37. while (rdr.Read()) {
  38. TypeITTableBigPartial obj = new TypeITTableBigPartial();
  39. if (!rdr.IsDBNull(0)) obj.Id = Convert.ToInt64(rdr.GetValue(0));
  40. if (!rdr.IsDBNull(1)) obj.ColInteger = Convert.ToInt64(rdr.GetValue(1));
  41. if (!rdr.IsDBNull(2)) obj.ColNumber = (Decimal?)OracleDecimal.SetPrecision(rdr.GetOracleDecimal(2), 28);
  42. if (!rdr.IsDBNull(3)) obj.ColVarchar2Max = Convert.ToString(rdr.GetValue(3));
  43. if (!rdr.IsDBNull(4)) obj.ColDate = Convert.ToDateTime(rdr.GetValue(4));
  44. if (!rdr.IsDBNull(5)) obj.ColTimestamp = (OracleTimeStamp?)rdr.GetOracleValue(5);
  45. __ret.Add(obj);
  46. if (optionalMaxNumberRowsToReadFromAnyCursor != null && __ret.Count >= optionalMaxNumberRowsToReadFromAnyCursor) break;
  47. }
  48. }
  49. return __ret;
  50. } // ReadResultITTableBigPartial
  51. public IList<TypeITTableBigPartial> GetRowsTypedRet<TypeITTableBigPartial>(Decimal? pInNumber, ref String pInOutVarchar2, ref IList<Int64?> pInOutAssocarrayInteger, out DateTime? pOutDate,
  52. UInt32? optionalMaxNumberRowsToReadFromAnyCursor = null, OracleConnection optionalPreexistingOpenConnection = null)
  53. where TypeITTableBigPartial : class, ITTableBigPartial, new() {
  54. IList<TypeITTableBigPartial> __ret = new List<TypeITTableBigPartial>(); pOutDate = null;
  55. OracleConnection __conn = optionalPreexistingOpenConnection ?? GetConnection();
  56. try {
  57. using (OracleCommand __cmd = new OracleCommand("ODPT.XMPL_PKG_EXAMPLE.GET_ROWS_TYPED_RET", __conn)) {
  58. __cmd.CommandType = CommandType.StoredProcedure;
  59. __cmd.BindByName = true;
  60. __cmd.Parameters.Add(new OracleParameter("!RETURN", OracleDbType.RefCursor, null, ParameterDirection.ReturnValue));
  61. __cmd.Parameters.Add(new OracleParameter("P_IN_NUMBER", OracleDbType.Decimal, pInNumber, ParameterDirection.Input));
  62. __cmd.Parameters.Add(new OracleParameter("P_IN_OUT_VARCHAR2", OracleDbType.Varchar2, 32767, pInOutVarchar2, ParameterDirection.InputOutput));
  63. __cmd.Parameters.Add(new OracleParameter("P_IN_OUT_ASSOCARRAY_INTEGER", OracleDbType.Int64, 50000, null, ParameterDirection.InputOutput));
  64. __cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].Value = (pInOutAssocarrayInteger == null || pInOutAssocarrayInteger.Count == 0 ? new Int64?[]{} : pInOutAssocarrayInteger.ToArray());
  65. __cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].CollectionType = OracleCollectionType.PLSQLAssociativeArray;
  66. __cmd.Parameters.Add(new OracleParameter("P_OUT_DATE", OracleDbType.Date, null, ParameterDirection.Output));
  67. OracleCommandTrace __cmdTrace = IsTracing(__cmd) ? new OracleCommandTrace(__cmd) : null;
  68. int __rowsAffected = __cmd.ExecuteNonQuery();
  69. if (!((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).IsNull)
  70. using (OracleDataReader __rdr = ((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).GetDataReader()) {
  71. __ret = ReadResultITTableBigPartial<TypeITTableBigPartial>(__rdr, optionalMaxNumberRowsToReadFromAnyCursor);
  72. } // using OracleDataReader
  73. pInOutVarchar2 = __cmd.Parameters["P_IN_OUT_VARCHAR2"].Status == OracleParameterStatus.NullFetched
  74. ? (String)null
  75. : Convert.ToString(__cmd.Parameters["P_IN_OUT_VARCHAR2"].Value.ToString());
  76. pInOutAssocarrayInteger = new List<Int64?>();
  77. for (int _i = 0; _i < (__cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].Value as OracleDecimal[]).Length; _i++)
  78. pInOutAssocarrayInteger.Add((__cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].Value as OracleDecimal[])[_i].IsNull
  79. ? (Int64?)null
  80. : Convert.ToInt64(((__cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].Value as OracleDecimal[])[_i].ToString())));
  81. pOutDate = __cmd.Parameters["P_OUT_DATE"].Status == OracleParameterStatus.NullFetched
  82. ? (DateTime?)null
  83. : Convert.ToDateTime(__cmd.Parameters["P_OUT_DATE"].Value.ToString());
  84. if (__cmdTrace != null) TraceCompletion(__cmdTrace, __ret.Count);
  85. } // using OracleCommand
  86. } finally {
  87. if (optionalPreexistingOpenConnection == null) {
  88. __conn.Close();
  89. __conn.Dispose();
  90. }
  91. }
  92. return __ret;
  93. } // GetRowsTypedRet
  94. public IList<TypeReturnUntyped> GetRowsUntypedRet<TypeReturnUntyped>(Int64? pInInteger,
  95. bool mapColumnToObjectPropertyByPosition = false, bool allowUnmappedColumnsToBeExcluded = false, UInt32? optionalMaxNumberRowsToReadFromAnyCursor = null,
  96. OracleConnection optionalPreexistingOpenConnection = null)
  97. where TypeReturnUntyped : class, new() {
  98. IList<TypeReturnUntyped> __ret = new List<TypeReturnUntyped>();
  99. OracleConnection __conn = optionalPreexistingOpenConnection ?? GetConnection();
  100. try {
  101. using (OracleCommand __cmd = new OracleCommand("ODPT.XMPL_PKG_EXAMPLE.GET_ROWS_UNTYPED_RET", __conn)) {
  102. __cmd.CommandType = CommandType.StoredProcedure;
  103. __cmd.BindByName = true;
  104. __cmd.Parameters.Add(new OracleParameter("!RETURN", OracleDbType.RefCursor, null, ParameterDirection.ReturnValue));
  105. __cmd.Parameters.Add(new OracleParameter("P_IN_INTEGER", OracleDbType.Int64, pInInteger, ParameterDirection.Input));
  106. OracleCommandTrace __cmdTrace = IsTracing(__cmd) ? new OracleCommandTrace(__cmd) : null;
  107. int __rowsAffected = __cmd.ExecuteNonQuery();
  108. if (!((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).IsNull)
  109. using (OracleDataReader __rdr = ((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).GetDataReader()) {
  110. __ret = Hydrator.ReadResult<TypeReturnUntyped>(__rdr, mapColumnToObjectPropertyByPosition, allowUnmappedColumnsToBeExcluded, optionalMaxNumberRowsToReadFromAnyCursor);
  111. } // using OracleDataReader
  112. if (__cmdTrace != null) TraceCompletion(__cmdTrace, __ret.Count);
  113. } // using OracleCommand
  114. } finally {
  115. if (optionalPreexistingOpenConnection == null) {
  116. __conn.Close();
  117. __conn.Dispose();
  118. }
  119. }
  120. return __ret;
  121. } // GetRowsUntypedRet
  122. public DataTable GetRowsUntypedRet(Int64? pInInteger, Boolean convertColumnNameToTitleCaseInCaption = false, UInt32? optionalMaxNumberRowsToReadFromAnyCursor = null, OracleConnection optionalPreexistingOpenConnection = null) {
  123. DataTable __ret = null;
  124. OracleConnection __conn = optionalPreexistingOpenConnection ?? GetConnection();
  125. try {
  126. using (OracleCommand __cmd = new OracleCommand("ODPT.XMPL_PKG_EXAMPLE.GET_ROWS_UNTYPED_RET", __conn)) {
  127. __cmd.CommandType = CommandType.StoredProcedure;
  128. __cmd.BindByName = true;
  129. __cmd.Parameters.Add(new OracleParameter("!RETURN", OracleDbType.RefCursor, null, ParameterDirection.ReturnValue));
  130. __cmd.Parameters.Add(new OracleParameter("P_IN_INTEGER", OracleDbType.Int64, pInInteger, ParameterDirection.Input));
  131. OracleCommandTrace __cmdTrace = IsTracing(__cmd) ? new OracleCommandTrace(__cmd) : null;
  132. int __rowsAffected = __cmd.ExecuteNonQuery();
  133. if (!((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).IsNull)
  134. using (OracleDataReader __rdr = ((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).GetDataReader()) {
  135. __ret = Hydrator.ReadResult(__rdr, convertColumnNameToTitleCaseInCaption, optionalMaxNumberRowsToReadFromAnyCursor);
  136. } // using OracleDataReader
  137. if (__cmdTrace != null) TraceCompletion(__cmdTrace, __ret.Rows.Count);
  138. } // using OracleCommand
  139. } finally {
  140. if (optionalPreexistingOpenConnection == null) {
  141. __conn.Close();
  142. __conn.Dispose();
  143. }
  144. }
  145. return __ret;
  146. } // GetRowsUntypedRet
  147. } // XmplPkgExample
  148. } // Schema.Odpt.Xmpl.Package
Executing Generated C# 4.0 Code - Example/Example.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Diagnostics;
  5. using Schema.Odpt.Xmpl.Package; // generated code for packages
  6. using Oracle.ManagedDataAccess.Types; // ODP.NET safe types
  7. using Odapter; // attribute used to map by position
  8. namespace OdapterExample {
  9. class Program {
  10. static void Main(string[] args) {
  11. (new Example()).Run();
  12. }
  13. }
  14. // The following DTO classes will be used in different ways for the same result set.
  15. // Inherits the package record type DTO, adding custom properties
  16. public class DtoImplemented : XmplPkgExample.ITTableBigPartial { // no mapping required
  17. public Int64? Id { get; set; }
  18. public Int64? ColInteger { get; set; }
  19. public Decimal? ColNumber { get; set; }
  20. public String ColVarchar2Max { get; set; }
  21. public DateTime? ColDate { get; set; }
  22. public OracleTimeStamp? ColTimestamp { get; set; } // ODP.NET safe type struct
  23. }
  24. // Implements the package record type's interface, adding custom properties
  25. public class DtoImplementedWithCustom : XmplPkgExample.ITTableBigPartial { // no mapping required
  26. public Int64? Id { get; set; }
  27. public Int64? ColInteger { get; set; }
  28. public Decimal? ColNumber { get; set; }
  29. public String ColVarchar2Max { get; set; }
  30. public DateTime? ColDate { get; set; }
  31. public OracleTimeStamp? ColTimestamp { get; set; } // ODP.NET safe type struct
  32. public String StringPropertyExtra { get; set; } // custom property
  33. public List<Int32> Int32ListPropertyExtra { get; set; } // custom property
  34. }
  35. // Custom DTO for map by name with only 4 column properties (Date, Timestamp col excluded)
  36. public class DtoCustomMapByName { // Column type and name must match, order and alias irrelvant
  37. public Int64? Id { get; set; } // maps id to PascalCase public property
  38. public Int64? ColInteger { get; set; } // maps col_integer to PascalCase public property
  39. protected Decimal? colNumber; // maps col_number to camelCase non-public field
  40. public Decimal? MyNumber { get { return colNumber; } set { colNumber = value; } } // PascalCase public property will not map
  41. private String _colVarchar2Max; // maps col_varchar2_max to underscore prefixed camelCase non-public field
  42. public virtual String MyVarchar2Max { get { return _colVarchar2Max; } set { _colVarchar2Max = value; } } // PascalCase public property will not map
  43. public String StringPropertyExtra { get; set; } // custom property
  44. public List<Int32> Int32ListPropertyExtra { get; set; } // custom property
  45. }
  46. // Custom DTO for map by position with only 4 column properties (Date, Timestamp cols excluded)
  47. public class DtoCustomMapByPosition { // Column type and order must match, name and alias irrelevant.
  48. [HydratorMapAttribute(Position = 0)] // maps to column 0 (first column)
  49. public Int64? MyCol1 { get; set; }
  50. [HydratorMapAttribute(Position = 1)] // maps to column 1
  51. public Int64? MyCol2 { get; set; }
  52. [HydratorMapAttribute(Position = 2)] // maps to column 2
  53. public Decimal? MyCol3 { get; set; }
  54. [HydratorMapAttribute(Position = 3)] // maps to column 3
  55. public String MyCol4 { get; set; }
  56. public String StringPropertyExtra { get; set; } // custom property
  57. public List<Int32> Int32ListPropertyExtra { get; set; } // custom property
  58. }
  59. public class Example {
  60. private const String HELLO = "Hello", GOODBYE = "Goodbye";
  61. public void Run() {
  62. (new OdapterExample.Example()).Test();
  63. }
  64. public void Test() {
  65. uint? rowLimit = 25; // limit result sets to 25 rows, underlying table has over 1000 rows
  66. Int64? pInInt64 = 999999999999999999; // 18 digit long
  67. Decimal? pInDecimal = 79228162514264337593543950335M; // 28 digit decimal (Decimal.MaxValue)
  68. String pInOutString = HELLO;
  69. DateTime? pOutDate;
  70. // List used as argument for Oracle associative array
  71. IList<Int64?> pInOutListInt64, somePrimeNumbers = new List<Int64?> { 2, 3, 5, 7, 11, 13, 17, 19, 29, 31 };
  72. // DTO IList<T>s and a datatable to be hydrated from Oracle cursor
  73. IList<DtoImplemented> dtoInheritedResultSet;
  74. IList<DtoImplementedWithCustom> dtoImplementedResultSet;
  75. IList<DtoCustomMapByName> dtoOriginalMapByNameResultSet;
  76. IList<DtoCustomMapByPosition> dtoOriginalMapByPositionLResultSet;
  77. DataTable dataTable;
  78. // 1. Hydrate DTO IList<T> from typed result set by using DTO implementing package record interface.
  79. pInOutListInt64 = somePrimeNumbers;
  80. dtoInheritedResultSet = XmplPkgExample.Instance.GetRowsTypedRet<DtoImplemented>(pInDecimal, ref pInOutString, ref pInOutListInt64, out pOutDate, rowLimit);
  81. Debug.Assert(dtoInheritedResultSet.Count == rowLimit);
  82. Debug.Assert(pInOutString.Equals(GOODBYE)); // confirm OUT string arg from package function
  83. for (int i = 0; i < pInOutListInt64.Count; i++)
  84. Debug.Assert(pInOutListInt64[i].Equals(somePrimeNumbers[i] * 7)); // confirm all values were multiplied by 7 in func
  85. Debug.Assert(pOutDate.Equals(new DateTime(1999, 12, 31))); // confirm OUT date arg from package function
  86. // 2. Hydrate DTO IList<T> from typed result set by using DTO implementing package record interface with additional properties.
  87. pInOutListInt64 = somePrimeNumbers;
  88. dtoImplementedResultSet = XmplPkgExample.Instance.GetRowsTypedRet<DtoImplementedWithCustom>(pInDecimal, ref pInOutString, ref pInOutListInt64, out pOutDate, rowLimit);
  89. Debug.Assert(dtoImplementedResultSet.Count == rowLimit);
  90. Debug.Assert(pInOutString.Equals(GOODBYE)); // confirm OUT string arg from package function
  91. for (int i = 0; i < pInOutListInt64.Count; i++)
  92. Debug.Assert(pInOutListInt64[i].Equals(somePrimeNumbers[i] * 7)); // confirm all values were multiplied by 7 in func
  93. Debug.Assert(pOutDate.Equals(new DateTime(1999, 12, 31))); // confirm OUT date arg from package function
  94. // 3. Hydrate DTO IList<T> from untyped result set by mapping column name to property name (default);
  95. // unmapped columns will be ignored (non-default).
  96. dtoOriginalMapByNameResultSet = XmplPkgExample.Instance.GetRowsUntypedRet<DtoCustomMapByName>(pInInt64, false, true, rowLimit);
  97. Debug.Assert(dtoOriginalMapByNameResultSet.Count == rowLimit);
  98. // 4. Hydrate DTO IList<T> from untyped result set by mapping column name to property name (default);
  99. // an unmapped column will throw (default).
  100. try {
  101. dtoOriginalMapByNameResultSet = XmplPkgExample.Instance.GetRowsUntypedRet<DtoCustomMapByName>(pInInt64, false, false, rowLimit);
  102. } catch (Exception ex) {
  103. if (!ex.Message.StartsWith("Hydrator.BuildMappings")) Debug.Assert(false);
  104. }
  105. // 5. Hydrate DTO IList<T> from untyped result set by mapping column position to property position (non-default);
  106. // unmapped columns will be ignored (non-default)
  107. dtoOriginalMapByPositionLResultSet = XmplPkgExample.Instance.GetRowsUntypedRet<DtoCustomMapByPosition>(pInInt64, true, true, rowLimit);
  108. // 6. Hydrate DTO IList<T> from untyped result set by mapping column position to property position (non-default);
  109. // an unmapped column will throw (default).
  110. try {
  111. dtoOriginalMapByPositionLResultSet = XmplPkgExample.Instance.GetRowsUntypedRet<DtoCustomMapByPosition>(pInInt64, true, false, rowLimit);
  112. } catch (Exception ex) {
  113. if (!ex.Message.StartsWith("Hydrator.BuildMappings")) Debug.Assert(false);
  114. }
  115. // 7. Hydrate Datatable from all columns in untyped result set, column names are converted to DataTable captions.
  116. // No DTO or generic required.
  117. dataTable = XmplPkgExample.Instance.GetRowsUntypedRet(pInInt64, true, rowLimit);
  118. Debug.Assert(dataTable.Rows.Count == rowLimit);
  119. List<String> dataTableCaptions = new List<string> { "Id", "Col Integer", "Col Number", "Varchar2 Max Col", "Col Date", "Col Timestamp" };
  120. for (int i = 0; i < dataTableCaptions.Count; i++)
  121. Debug.Assert(dataTable.Columns[i].Caption.Equals(dataTableCaptions[i])); // confirm captions were created from column name
  122. }
  123. }
  124. }
Generation for C# 9.0

Generated C# 9.0 Code - Example.NET5/generated/OdptXmplPackage.cs
  1. //------------------------------------------------------------------------------
  2. // <auto-generated>
  3. // This code was auto-generated by Odapter 2.01 on Wed, 09 Jun 2021 19:26:48 GMT.
  4. // Direct edits will be lost if the code is regenerated.
  5. // </auto-generated>
  6. //------------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Data;
  10. using System.Data.Common;
  11. using Oracle.ManagedDataAccess.Client;
  12. using Oracle.ManagedDataAccess.Types;
  13. using System.Collections;
  14. using System.Diagnostics;
  15. using System.Runtime.Serialization;
  16. using System.Xml;
  17. using System.Xml.Serialization;
  18. using System.Linq;
  19. using Odapter;
  20. namespace Schema.Odpt.Xmpl.Package {
  21. public sealed partial class XmplPkgExample : Schema.Odpt.Xmpl.OdptAdapter {
  22. private XmplPkgExample() { }
  23. private static readonly XmplPkgExample _instance = new XmplPkgExample();
  24. public static XmplPkgExample Instance { get { return _instance; } }
  25. public interface ITTableBigPartial {
  26. Int64? Id { get; init; }
  27. Int64? ColInteger { get; init; }
  28. Decimal? ColNumber { get; init; }
  29. String ColVarchar2Max { get; init; }
  30. DateTime? ColDate { get; init; }
  31. OracleTimeStamp? ColTimestamp { get; init; }
  32. } // ITTableBigPartial
  33. public IList<TypeITTableBigPartial> GetRowsTypedRet<TypeITTableBigPartial>(Decimal? pInNumber, ref String pInOutVarchar2, ref IList<Int64?> pInOutAssocarrayInteger, out DateTime? pOutDate,
  34. UInt32? optionalMaxNumberRowsToReadFromAnyCursor = null, OracleConnection optionalPreexistingOpenConnection = null)
  35. where TypeITTableBigPartial : class, ITTableBigPartial, new() {
  36. IList<TypeITTableBigPartial> __ret = new List<TypeITTableBigPartial>(); pOutDate = null;
  37. OracleConnection __conn = optionalPreexistingOpenConnection ?? GetConnection();
  38. try {
  39. using (OracleCommand __cmd = new OracleCommand("ODPT.XMPL_PKG_EXAMPLE.GET_ROWS_TYPED_RET", __conn)) {
  40. __cmd.CommandType = CommandType.StoredProcedure;
  41. __cmd.BindByName = true;
  42. __cmd.Parameters.Add(new OracleParameter("!RETURN", OracleDbType.RefCursor, null, ParameterDirection.ReturnValue));
  43. __cmd.Parameters.Add(new OracleParameter("P_IN_NUMBER", OracleDbType.Decimal, pInNumber, ParameterDirection.Input));
  44. __cmd.Parameters.Add(new OracleParameter("P_IN_OUT_VARCHAR2", OracleDbType.Varchar2, 32767, pInOutVarchar2, ParameterDirection.InputOutput));
  45. __cmd.Parameters.Add(new OracleParameter("P_IN_OUT_ASSOCARRAY_INTEGER", OracleDbType.Int64, 65535, null, ParameterDirection.InputOutput));
  46. __cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].Value = (pInOutAssocarrayInteger == null || pInOutAssocarrayInteger.Count == 0 ? new Int64?[]{} : pInOutAssocarrayInteger.ToArray());
  47. __cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].CollectionType = OracleCollectionType.PLSQLAssociativeArray;
  48. __cmd.Parameters.Add(new OracleParameter("P_OUT_DATE", OracleDbType.Date, null, ParameterDirection.Output));
  49. OracleCommandTrace __cmdTrace = IsTracing(__cmd) ? new OracleCommandTrace(__cmd) : null;
  50. int __rowsAffected = __cmd.ExecuteNonQuery();
  51. if (!((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).IsNull)
  52. using (OracleDataReader __rdr = ((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).GetDataReader()) {
  53. __ret = Hydrator.ReadResult<TypeITTableBigPartial>(__rdr, false, false, optionalMaxNumberRowsToReadFromAnyCursor);
  54. } // using OracleDataReader
  55. pInOutVarchar2 = __cmd.Parameters["P_IN_OUT_VARCHAR2"].Status == OracleParameterStatus.NullFetched
  56. ? (String)null
  57. : Convert.ToString(__cmd.Parameters["P_IN_OUT_VARCHAR2"].Value.ToString());
  58. pInOutAssocarrayInteger = new List<Int64?>();
  59. for (int _i = 0; _i < (__cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].Value as OracleDecimal[]).Length; _i++)
  60. pInOutAssocarrayInteger.Add((__cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].Value as OracleDecimal[])[_i].IsNull
  61. ? (Int64?)null
  62. : Convert.ToInt64(((__cmd.Parameters["P_IN_OUT_ASSOCARRAY_INTEGER"].Value as OracleDecimal[])[_i].ToString())));
  63. pOutDate = __cmd.Parameters["P_OUT_DATE"].Status == OracleParameterStatus.NullFetched
  64. ? (DateTime?)null
  65. : Convert.ToDateTime(__cmd.Parameters["P_OUT_DATE"].Value.ToString());
  66. if (__cmdTrace != null) TraceCompletion(__cmdTrace, __ret.Count);
  67. } // using OracleCommand
  68. } finally {
  69. if (optionalPreexistingOpenConnection == null) {
  70. __conn.Close();
  71. __conn.Dispose();
  72. }
  73. }
  74. return __ret;
  75. } // GetRowsTypedRet
  76. public IList<TypeReturnUntyped> GetRowsUntypedRet<TypeReturnUntyped>(Int64? pInInteger,
  77. bool mapColumnToObjectPropertyByPosition = false, bool allowUnmappedColumnsToBeExcluded = false, UInt32? optionalMaxNumberRowsToReadFromAnyCursor = null,
  78. OracleConnection optionalPreexistingOpenConnection = null)
  79. where TypeReturnUntyped : class, new() {
  80. IList<TypeReturnUntyped> __ret = new List<TypeReturnUntyped>();
  81. OracleConnection __conn = optionalPreexistingOpenConnection ?? GetConnection();
  82. try {
  83. using (OracleCommand __cmd = new OracleCommand("ODPT.XMPL_PKG_EXAMPLE.GET_ROWS_UNTYPED_RET", __conn)) {
  84. __cmd.CommandType = CommandType.StoredProcedure;
  85. __cmd.BindByName = true;
  86. __cmd.Parameters.Add(new OracleParameter("!RETURN", OracleDbType.RefCursor, null, ParameterDirection.ReturnValue));
  87. __cmd.Parameters.Add(new OracleParameter("P_IN_INTEGER", OracleDbType.Int64, pInInteger, ParameterDirection.Input));
  88. OracleCommandTrace __cmdTrace = IsTracing(__cmd) ? new OracleCommandTrace(__cmd) : null;
  89. int __rowsAffected = __cmd.ExecuteNonQuery();
  90. if (!((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).IsNull)
  91. using (OracleDataReader __rdr = ((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).GetDataReader()) {
  92. __ret = Hydrator.ReadResult<TypeReturnUntyped>(__rdr, mapColumnToObjectPropertyByPosition, allowUnmappedColumnsToBeExcluded, optionalMaxNumberRowsToReadFromAnyCursor);
  93. } // using OracleDataReader
  94. if (__cmdTrace != null) TraceCompletion(__cmdTrace, __ret.Count);
  95. } // using OracleCommand
  96. } finally {
  97. if (optionalPreexistingOpenConnection == null) {
  98. __conn.Close();
  99. __conn.Dispose();
  100. }
  101. }
  102. return __ret;
  103. } // GetRowsUntypedRet
  104. public DataTable GetRowsUntypedRet(Int64? pInInteger, Boolean convertColumnNameToTitleCaseInCaption = false, UInt32? optionalMaxNumberRowsToReadFromAnyCursor = null, OracleConnection optionalPreexistingOpenConnection = null) {
  105. DataTable __ret = null;
  106. OracleConnection __conn = optionalPreexistingOpenConnection ?? GetConnection();
  107. try {
  108. using (OracleCommand __cmd = new OracleCommand("ODPT.XMPL_PKG_EXAMPLE.GET_ROWS_UNTYPED_RET", __conn)) {
  109. __cmd.CommandType = CommandType.StoredProcedure;
  110. __cmd.BindByName = true;
  111. __cmd.Parameters.Add(new OracleParameter("!RETURN", OracleDbType.RefCursor, null, ParameterDirection.ReturnValue));
  112. __cmd.Parameters.Add(new OracleParameter("P_IN_INTEGER", OracleDbType.Int64, pInInteger, ParameterDirection.Input));
  113. OracleCommandTrace __cmdTrace = IsTracing(__cmd) ? new OracleCommandTrace(__cmd) : null;
  114. int __rowsAffected = __cmd.ExecuteNonQuery();
  115. if (!((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).IsNull)
  116. using (OracleDataReader __rdr = ((OracleRefCursor)__cmd.Parameters["!RETURN"].Value).GetDataReader()) {
  117. __ret = Hydrator.ReadResult(__rdr, convertColumnNameToTitleCaseInCaption, optionalMaxNumberRowsToReadFromAnyCursor);
  118. } // using OracleDataReader
  119. if (__cmdTrace != null) TraceCompletion(__cmdTrace, __ret.Rows.Count);
  120. } // using OracleCommand
  121. } finally {
  122. if (optionalPreexistingOpenConnection == null) {
  123. __conn.Close();
  124. __conn.Dispose();
  125. }
  126. }
  127. return __ret;
  128. } // GetRowsUntypedRet
  129. } // XmplPkgExample
  130. } // Schema.Odpt.Xmpl.Package
Executing Generated C# 9.0 Code - Example.NET5/Example.NET5.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Diagnostics;
  5. using Schema.Odpt.Xmpl.Package; // generated code for packages
  6. using Oracle.ManagedDataAccess.Types; // ODP.NET safe types
  7. using Odapter; // attribute used to map by position
  8. namespace OdapterExample.NET5 {
  9. class Program {
  10. static void Main(string[] args) {
  11. (new Example()).Run();
  12. }
  13. }
  14. // The following DTO classes will be used in different ways for the same result set.
  15. // Implements the package record's immutable interface
  16. public record DtoImplemented : XmplPkgExample.ITTableBigPartial { // no mapping required
  17. public Int64? Id { get; init; }
  18. public Int64? ColInteger { get; init; }
  19. public Decimal? ColNumber { get; init; }
  20. public String ColVarchar2Max { get; init; }
  21. public DateTime? ColDate { get; init; }
  22. public OracleTimeStamp? ColTimestamp { get; init; } // ODP.NET safe type struct
  23. }
  24. // Implements the package record's immutable interface Custom positional record (w/ parameterless constructor) DTO with only 4 column properties (Date and Timestamp columns are excluded)
  25. public record DtoImplementedPositionalRecord(
  26. Int64? Id,
  27. Int64? ColInteger,
  28. Decimal? ColNumber,
  29. String ColVarchar2Max,
  30. DateTime? ColDate,
  31. OracleTimeStamp? ColTimestamp) : XmplPkgExample.ITTableBigPartial { // no mapping required
  32. public DtoImplementedPositionalRecord() : this(default, default, default, default, default, default) { }
  33. }
  34. // Implements the package record's immutable interface, adding custom properties
  35. public record DtoImplementedWithCustom : XmplPkgExample.ITTableBigPartial { // no mapping required
  36. public Int64? Id { get; init; }
  37. public Int64? ColInteger { get; init; }
  38. public Decimal? ColNumber { get; init; }
  39. public String ColVarchar2Max { get; init; }
  40. public DateTime? ColDate { get; init; }
  41. public OracleTimeStamp? ColTimestamp { get; init; } // ODP.NET safe type struct
  42. public String StringPropertyExtra { get; init; } // custom property, can be ignored during hydration
  43. public List<Int32> Int32ListPropertyExtra { get; init; } // custom property, can be ignored during hydration
  44. }
  45. // Custom DTO for mapping by name hydration with only 4 column properties (Date and Timestamp columns are excluded)
  46. public record DtoCustomMapByName { // Column type and name must match, order and alias irrelvant
  47. public Int64? Id { get; init; } // maps id to PascalCase public property
  48. public Int64? ColInteger { get; init; } // maps col_integer to PascalCase public property
  49. public Decimal? MyNumber { // PascalCase public property will not map
  50. get { return colNumber; } set { colNumber = value; }
  51. } protected Decimal? colNumber; // maps col_number to camelCase non-public field
  52. public virtual String MyVarchar2Max // PascalCase public property will not map
  53. { get { return _colVarchar2Max; } set { _colVarchar2Max = value; }
  54. } private String _colVarchar2Max; // maps col_varchar2_max to underscore prefixed camelCase non-public field
  55. // custom properties, can be ignored during hydration
  56. public String StringPropertyExtra { get; init; }
  57. public List<Int32> Int32ListPropertyExtra { get; init; }
  58. }
  59. // Custom DTO for mappping by position for hydration with only 4 column properties (Date and Timestamp columns are excluded)
  60. public record DtoCustomMapByPosition { // Column type and order must match, name and alias irrelevant.
  61. [HydratorMapAttribute(Position = 0)] // maps to column 0 (first column)
  62. public Int64? MyCol1 { get; init; }
  63. [HydratorMapAttribute(Position = 1)] // maps to column 1
  64. public Int64? MyCol2 { get; init; }
  65. [HydratorMapAttribute(Position = 2)] // maps to column 2
  66. public Decimal? MyCol3 { get; init; }
  67. [HydratorMapAttribute(Position = 3)] // maps to column 3
  68. public String MyCol4 { get; init; }
  69. // custom properties, can be ignored during hydration
  70. public String StringPropertyExtra { get; init; }
  71. public List<Int32> Int32ListPropertyExtra { get; init; }
  72. }
  73. public class Example {
  74. private const String HELLO = "Hello", GOODBYE = "Goodbye";
  75. public void Run() {
  76. (new OdapterExample.NET5.Example()).Test();
  77. }
  78. public void Test() {
  79. uint? rowLimit = 25; // limit result sets to 25 rows, underlying table has over 1000 rows
  80. Int64? pInInt64 = 999999999999999999; // 18 digit long
  81. Decimal? pInDecimal = 79228162514264337593543950335M; // 28 digit decimal (Decimal.MaxValue)
  82. String pInOutString = HELLO;
  83. DateTime? pOutDate;
  84. // List used as argument for Oracle associative array
  85. IList<Int64?> pInOutListInt64, somePrimeNumbers = new List<Int64?> { 2, 3, 5, 7, 11, 13, 17, 19, 29, 31 };
  86. // 1a. Hydrate DTO IList<T> from typed result set by using DTO implementing package record interface.
  87. pInOutListInt64 = somePrimeNumbers;
  88. Debug.Assert(XmplPkgExample.Instance.GetRowsTypedRet<DtoImplemented>(pInDecimal, ref pInOutString, ref pInOutListInt64, out pOutDate, rowLimit).Count == rowLimit);
  89. Debug.Assert(pInOutString.Equals(GOODBYE)); // confirm OUT string arg from package function
  90. for (int i = 0; i < pInOutListInt64.Count; i++)
  91. Debug.Assert(pInOutListInt64[i].Equals(somePrimeNumbers[i] * 7)); // confirm all values were multiplied by 7 in func
  92. Debug.Assert(pOutDate.Equals(new DateTime(1999, 12, 31))); // confirm OUT date arg from package function
  93. // 1b. Hydrate DTO IList<T> from typed result set by using DTO positional record implementing package record interface.
  94. pInOutListInt64 = somePrimeNumbers;
  95. Debug.Assert(XmplPkgExample.Instance.GetRowsTypedRet<DtoImplementedPositionalRecord>(pInDecimal, ref pInOutString, ref pInOutListInt64, out pOutDate, rowLimit).Count == rowLimit);
  96. Debug.Assert(pInOutString.Equals(GOODBYE)); // confirm OUT string arg from package function
  97. for (int i = 0; i < pInOutListInt64.Count; i++)
  98. Debug.Assert(pInOutListInt64[i].Equals(somePrimeNumbers[i] * 7)); // confirm all values were multiplied by 7 in func
  99. Debug.Assert(pOutDate.Equals(new DateTime(1999, 12, 31))); // confirm OUT date arg from package function
  100. // 2. Hydrate DTO IList<T> from typed result set by using DTO implementing package record interface with additional properties.
  101. pInOutListInt64 = somePrimeNumbers;
  102. Debug.Assert(XmplPkgExample.Instance.GetRowsTypedRet<DtoImplementedWithCustom>(pInDecimal, ref pInOutString, ref pInOutListInt64, out pOutDate, rowLimit).Count == rowLimit);
  103. Debug.Assert(pInOutString.Equals(GOODBYE)); // confirm OUT string arg from package function
  104. for (int i = 0; i < pInOutListInt64.Count; i++)
  105. Debug.Assert(pInOutListInt64[i].Equals(somePrimeNumbers[i] * 7)); // confirm all values were multiplied by 7 in func
  106. Debug.Assert(pOutDate.Equals(new DateTime(1999, 12, 31))); // confirm OUT date arg from package function
  107. // 3a. Hydrate DTO IList<T> from untyped result set by mapping column name to property name using custom positional record DTO;
  108. // unmapped columns will be ignored.
  109. Debug.Assert(XmplPkgExample.Instance.GetRowsUntypedRet<DtoImplementedPositionalRecord>(pInInt64,
  110. mapColumnToObjectPropertyByPosition: false, // map by name
  111. allowUnmappedColumnsToBeExcluded: true,
  112. rowLimit).Count == rowLimit);
  113. // 3b. Hydrate DTO IList<T> from untyped result set by mapping column name to property name using custom DTO;
  114. // unmapped columns will be ignored (arg non-default).
  115. Debug.Assert(XmplPkgExample.Instance.GetRowsUntypedRet<DtoCustomMapByName>(pInInt64,
  116. mapColumnToObjectPropertyByPosition: false, // map by name
  117. allowUnmappedColumnsToBeExcluded: true,
  118. rowLimit).Count == rowLimit);
  119. // 4. Hydrate DTO IList<T> from untyped result set by mapping column name to property name custom DTO;
  120. // an unmapped column will throw.
  121. try {
  122. XmplPkgExample.Instance.GetRowsUntypedRet<DtoCustomMapByName>(pInInt64,
  123. mapColumnToObjectPropertyByPosition: false, // map by name
  124. allowUnmappedColumnsToBeExcluded: false,
  125. rowLimit);
  126. Debug.Assert(false);
  127. } catch (Exception ex) {
  128. if (!ex.Message.StartsWith("Hydrator.BuildMappings")) Debug.Assert(false);
  129. }
  130. // 5. Hydrate DTO IList<T> from untyped result set by mapping column position to property position using custom DTO with position attributes;
  131. // unmapped columns will be ignored (non-default)
  132. Debug.Assert(XmplPkgExample.Instance.GetRowsUntypedRet<DtoCustomMapByPosition>(pInInt64,
  133. mapColumnToObjectPropertyByPosition: false, // map by position
  134. allowUnmappedColumnsToBeExcluded: true,
  135. rowLimit).Count == rowLimit);
  136. // 6. Hydrate DTO IList<T> from untyped result set by mapping column position to property position using custom DTO with position attributes;
  137. // an unmapped column will throw (default).
  138. try {
  139. XmplPkgExample.Instance.GetRowsUntypedRet<DtoCustomMapByPosition>(pInInt64,
  140. mapColumnToObjectPropertyByPosition: false, // map by position
  141. allowUnmappedColumnsToBeExcluded: false,
  142. rowLimit);
  143. Debug.Assert(false);
  144. } catch (Exception ex) {
  145. if (!ex.Message.StartsWith("Hydrator.BuildMappings")) Debug.Assert(false);
  146. }
  147. // 7. Hydrate Datatable from all columns in untyped result set, column names are converted to DataTable captions.
  148. // No DTO or generic required.
  149. DataTable dataTable = XmplPkgExample.Instance.GetRowsUntypedRet(pInInt64, true, rowLimit);
  150. Debug.Assert(dataTable.Rows.Count == rowLimit);
  151. List<String> dataTableCaptions = new List<string> { "Id", "Col Integer", "Col Number", "Varchar2 Max Col", "Col Date", "Col Timestamp" };
  152. for (int i = 0; i < dataTableCaptions.Count; i++)
  153. Debug.Assert(dataTable.Columns[i].Caption.Equals(dataTableCaptions[i])); // confirm captions were created from column name
  154. }
  155. }
  156. }