diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a148b6be..85723c99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,57 @@ Copyright (c) Oracle and/or its affiliates. All rights reserved. -Oracle requires that contributors to all of its open-source projects sign the Oracle Contributor Agreement (OCA). +# Contributing to this repository -For pull requests to be accepted, the bottom of your commit message must have the following line using your name and e-mail address as it appears in the OCA Signatories list. +We welcome your contributions! There are multiple ways to contribute. -``` +## Opening issues + +For bugs or enhancement requests, please file a GitHub issue unless it's +security related. When filing a bug remember that the better written the bug is, +the more likely it is to be fixed. If you think you've found a security +vulnerability, do not raise a GitHub issue and follow the instructions in our +[security policy](./SECURITY.md). + +## Contributing code + +We welcome your code contributions. Before submitting code via a pull request, +you will need to have signed the [Oracle Contributor Agreement][OCA] (OCA) and +your commits need to include the following line using the name and e-mail +address you used to sign the OCA: + +```text Signed-off-by: Your Name ``` -Only pull requests from committers that can be verified as having signed the OCA can be accepted. +This can be automatically added to pull requests by committing with `--sign-off` +or `-s`, e.g. + +```text +git commit --signoff +``` + +Only pull requests from committers that can be verified as having signed the OCA +can be accepted. + +## Pull request process + +1. Ensure there is an issue created to track and discuss the fix or enhancement + you intend to submit. +1. Fork this repository. +1. Create a branch in your fork to implement the changes. We recommend using + the issue number as part of your branch name, e.g. `1234-fixes`. +1. Ensure that any documentation is updated with the changes that are required + by your change. +1. Ensure that any samples are updated if the base image has been changed. +1. Submit the pull request. *Do not leave the pull request blank*. Explain exactly + what your changes are meant to do and provide simple steps on how to validate. + your changes. Ensure that you reference the issue you created as well. +1. We will assign the pull request to 2-3 people for review before it is merged. + +## Code of conduct + +Follow the [Golden Rule](https://en.wikipedia.org/wiki/Golden_Rule). If you'd +like more specific guidelines, see the [Contributor Covenant Code of Conduct][COC]. + +[OCA]: https://oca.opensource.oracle.com +[COC]: https://www.contributor-covenant.org/version/1/4/code-of-conduct/ diff --git a/LICENSE b/LICENSE.txt similarity index 97% rename from LICENSE rename to LICENSE.txt index 5915d623..00256ced 100644 --- a/LICENSE +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 Oracle +Copyright (c) 2015, 2023 Oracle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 7dffbd80..d1bdc013 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,45 @@ -

Oracle .NET Code Sample Respository

-

About Oracle .NET

+# Oracle .NET Code Sample Repository + +## About Oracle .NET This repository provides .NET code samples for Oracle developers, specifically for Oracle Data Provider for .NET (ODP.NET) and other Oracle .NET components. .NET products for Oracle Database are free of charge. They consist of: -

Getting Started

-Oracle .NET components are bundled together and installed as part of Oracle Data Access Components (ODAC). Downloads and installation instructions are available from the OTN .NET Tech Center download page and NuGet Gallery. Oracle Developer Tools for VS Code can be downloaded from the VS Code Marketplace. Installation instructions are available as part of each download page. The installation instructions list the software prerequisites for the version downloaded. -

Tutorials

-For beginning Oracle .NET developers, these on-premises .NET database tutorials and Autonomous Database .NET tutorials will assist you in getting started with .NET application development with Oracle Database. Video tutorials are available from the Oracle .NET YouTube site. +## Getting Started +Oracle .NET components are available individually on NuGet Gallery or bundled together as part of Oracle Data Access Components (ODAC). Provider downloads are available from NuGet Gallery and Oracle .NET download page. Oracle Developer Tools for Visual Studio can be downloaded from the Visual Studio Marketplace. + +## Tutorials +For novice Oracle .NET developers, these on-premises .NET database tutorials and Autonomous Database .NET tutorials will assist you in getting started with .NET application development with Oracle Database. + +Oracle .NET video tutorials are available from the Oracle .NET YouTube site. + +For those that want to build an end-to-end basic .NET web app for Oracle Database in the cloud, try the .NET Development with Oracle Autonomous Database Quick Start. The tutorial takes about an hour to complete and is free. By the end, you will have a complete running .NET website and database. -

More Information

+## More Information +## Contributing + +This project welcomes contributions from the community. Before submitting a pull request, please [review our contribution guide](./CONTRIBUTING.md) + +## Security + +Please consult the [security guide](./SECURITY.md) for our responsible security vulnerability disclosure process + +## License + +Copyright (c) 2015, 2025 Oracle and/or its affiliates. + +Released under the MIT License diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..2ca81027 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,38 @@ +# Reporting security vulnerabilities + +Oracle values the independent security research community and believes that +responsible disclosure of security vulnerabilities helps us ensure the security +and privacy of all our users. + +Please do NOT raise a GitHub Issue to report a security vulnerability. If you +believe you have found a security vulnerability, please submit a report to +[secalert_us@oracle.com][1] preferably with a proof of concept. Please review +some additional information on [how to report security vulnerabilities to Oracle][2]. +We encourage people who contact Oracle Security to use email encryption using +[our encryption key][3]. + +We ask that you do not use other channels or contact the project maintainers +directly. + +Non-vulnerability related security issues including ideas for new or improved +security features are welcome on GitHub Issues. + +## Security updates, alerts and bulletins + +Security updates will be released on a regular cadence. Many of our projects +will typically release security fixes in conjunction with the +Oracle Critical Patch Update program. Additional +information, including past advisories, is available on our [security alerts][4] +page. + +## Security-related information + +We will provide security related information such as a threat model, considerations +for secure use, or any known security issues in our documentation. Please note +that labs and sample code are intended to demonstrate a concept and may not be +sufficiently hardened for production use. + +[1]: mailto:secalert_us@oracle.com +[2]: https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html +[3]: https://www.oracle.com/security-alerts/encryptionkey.html +[4]: https://www.oracle.com/security-alerts/ diff --git a/images/oracle-nuget.png b/images/oracle-nuget.png new file mode 100644 index 00000000..63fa31d0 Binary files /dev/null and b/images/oracle-nuget.png differ diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 00000000..c8627c08 --- /dev/null +++ b/samples/README.md @@ -0,0 +1,184 @@ +Managed ODP.NET and ODP.NET Core Code Samples +============================================= +You must have managed ODP.NET or ODP.NET Core installed. To run the samples, follow these directions: +1) Modify the Data Source attribute in the connection strings to connect to an Oracle database via Easy Connect (Plus), TNS connect descriptor, or TNS alias. +2) Most of these samples use the SCOTT or Human Resources (HR) schema.
+The SCOTT schema create scripts are located here: https://github.com/oracle/dotnet-db-samples/tree/master/schemas
+The HR schema create scripts are located here: https://github.com/oracle/db-sample-schemas +3) Add Oracle.ManagedDataAccess.dll to the sample application. +4) Review the README file in the samples subdirectory, if any. + +While these samples are designed for managed ODP.NET or ODP.NET Core, they generally can use unmanaged ODP.NET by incorporating Oracle.DataAccess.dll and +adding the unmanaged ODP.NET namespace reference (i.e. "using Oracle.DataAccess.Client;" and "using Oracle.DataAccess.Types;"). + +Running ODP.NET Core Samples from Command Line +============================================== +1) Install .NET Core SDK from Microsoft's website: https://dotnet.microsoft.com/download +2) Open a terminal such as PowerShell, command prompt, or bash. Enter the following commands to create and setup your ODP.NET Core sample:
+ A) dotnet new console --output (Sample Name)
+ B) dotnet add package Oracle.ManagedDataAccess.Core --version (e.g. 23.8.0) +4) Replace the contents of Program.cs with the GitHub sample code of interest. +5) Insert your user id, password, and data source. The sample will have its own README or comments to indicate additional configuration that may be required. +6) Run using the following command: dotnet run --project (Sample Name) + + +Below is the feature list the samples cover. Each feature's sample has its own subdirectory. + +AI Vector +---------------------- +* Search Vector Stores and Collections Sample: Load and vectorize data from .NET. Then, perform exact match searches and similarity searches against the data set. + +Application Continuity +---------------------- +* Sample 1: Unmanaged ODP.NET Application Continuity code sample with setup and runtime demo instructions. + +Parameter Array Binding +---------------------- +* Sample 1: Demonstrates parameter array binding. + +ASP.NET Core +------------ +* ASP.NET Core 2.x: Demonstrates a simple ASP.NET Core 2.x web app to connect and retrieve data.
+* ASP.NET Core 3.x: Demonstrates a simple ASP.NET Core 3.x web app to connect and retrieve data.
+* ASP.NET Core 6: Demonstrates a simple ASP.NET Core 6 web app to connect and retrieve data. + +PL/SQL Associative Array +------------------------ +* Sample 1: Demonstrates PL/SQL Associative Array binding. + +Async +----- +* Async Sample: Demonstrates using asynchronous ODP.NET (managed or core) and measures operation time.
+* Sync Sample: Demonstrates using synchronous ODP.NET (managed or core) and measures operation time to compare with async. + +Autonomous Database +------------------- +* ODP.NET Core Samples: Demonstrates how to connect ODP.NET Core to Oracle Autonomous Database via a console and an ASP.NET Core web app.
+* Managed ODP.NET Samples: Demonstrates how to connect managed ODP.NET to Oracle Autonomous Database via a console and an ASP.NET web app.
+* Unmanaged ODP.NET Sample: Demonstrates how to connect unmanaged ODP.NET to Oracle Autonomous Database via a console app. + +Azure Active Directory/Microsoft Entra ID +---------------------- +* Demonstrates connecting to Oracle Autonomous Database using a Microsoft Entra ID token with ODP.NET Core, managed, and unmanaged. + +Bulk Copy +--------- +* Sample 1: Demonstrates how to use ODP.NET bulk copy. Sample works for both managed and core ODP.NET. + +Client Factory +-------------- +* Sample 1: Demonstrates how to use the OracleClientFactory class. + +Command Builder +--------------- +* Sample 1: Demonstrates OracleCommandBuilder's SchemaSeparator property.
+* Sample 2: Demonstrates OracleCommandBuilders's QuoteIdentifier method.
+* Sample 3: Demonstrates OracleCommandBuilders's UnquoteIdentifier method. + +Configuration API +----------------- +* Samples demonstrate how to use the OracleConfiguration, OracleDataSourceCollection, and OracleOnsServerCollection classes. + +Connection +---------- +* Sample 1: Demonstrates OracleConnection's GetSchema() method.
+* Sample 2: Demonstrates all variations of OracleConnection's GetSchema(string) method overload.
+* Sample 3: Demonstrates all variations of OracleConnection's GetSchema(string, string[]) method overload. + +Connection String Builder +------------------------- +* Sample 1: Demonstrates how to use the OracleConnectionStringBuilder class. + +DataReader +---------- +* Unmanaged ODP.NET Sample: Demonstrates OracleDataReader's VisibleFieldCount and HiddenFieldCount properties.
+* ODP.NET Core Sample: Demonstrates how to connect and retrieve data using ODP.NET Core via a console app. + +Data Source Enumerator +---------------------- +* Sample 1: Demonstrates the functionality of OracleDataSourceEnumerator class. + +DataSet +------- +* Sample 1: Demonstrates data manipulation language (DML) operations on a Dataset.
+* Sample 2: Demonstrates how to populate a DataSet using C#.
+* Sample 3: Demonstrates DML operations on LOB columns.
+* Sample 4: Demonstrates how to populate a DataSet from multiple output Ref Cursors from a stored procedure.
+* Sample 5: Demonstrates how to populate a DataSet using Visual Basic .NET (VB.NET). + +Entity Framework Core +--------------------- +* Autonomous Database Sample: Demonstrates Oracle EF Core connecting to Oracle Autonomous Database.
+* Dependency Injection Sample: Demonstrates using dependency injection and ASP.NET Core with Oracle EF Core.
+* Getting Started Sample: Demonstrates a basic Oracle EF Core scenario using migrations and scaffolding.
+* JSON Columns Sample: Demonstrates how to create an owned entity, insert, query, update, and delete JSON column data.
+* Keyless Entity Types Sample: Demonstrates Oracle EF Core keyless entity types with relational and materialized views.
+* Stored Procedure Result Set Samples: Demonstrates using PL/SQL that returns either an explicitly or implicitly bound REF Cursor.
+* T4 Text Template Samples: Demonstrates data type mapping customization when scaffolding. + +Event Handler +------------- +* Sample 1: Demonstrates how to trap the OracleRowUpdatingEvent and OracleRowUpdatedEvent using VB.NET. + +Oracle Identity and Access Management +------------------------------------- +* Sample 1: Demonstrates how to use OCI .NET SDK to retrieve, authenticate, and refresh Oracle database tokens. + +JSON +---- +* Select JSON Sample: Demonstrates row insert into and query against a JSON table.
+* Select JSON CLOB Sample: Demonstrates row insert into and query against a JSON table using CLOB storage. + +LOB +--- +* Sample 1: Demonstrates how to populate and obtain LOB data from a DataSet.
+* Sample 2: Demonstrates how an OracleClob object is obtained as an output parameter of an anonymous PL/SQL block.
+* Sample 3: Demonstrates how an OracleClob object is obtained from an output parameter of a stored procedure.
+* Sample 4: Demonstrates how the LOB column data can be read as a .NET type by utilizing stream reads.
+* Sample 5: Demonstrates how to bind an OracleClob object as a parameter and refetch the newly updated CLOB data using an OracleDataReader and an OracleClob object.
+* Sample 6: Demonstrates LOB updates using row-level locking.
+* Sample 7: Demonstrates LOB updates using result set locking.
+* BFile Sample: Demonstrates accessing BFILEs through ODP.NET. + +OpenTelemetry +------------- +* Sample: Demonstrates using managed ODP.NET or ODP.NET Core with OpenTelemetry + +Performance Counters +-------------------- +* Sample 1: Demonstrates how to programmatically use ODP.NET performance counters. + +Pipelining and Async +-------------------- +* Pipelining and Async Sample: Demonstrates using pipelining and async ODP.NET (managed or core) and measures operation time.
+* No Pipelining and Sync Sample: Disables pipelining while using synchronous ODP.NET (managed or core) and measures operation time to compare with async and pipelining sample. + +Ref Cursor +---------- +* Sample 1: Demonstrates how a REF Cursor is obtained as an OracleDataReader.
+* Sample 2: Demonstrates how a REF Cursor is obtained as an OracleDataReader through the use of an OracleRefCursor object.
+* Sample 3: Demonstrates how multiple REF Cursors can be accessed by a single OracleDataReader.
+* Sample 4: Demonstrates how a DataSet can be populated from a REF Cursor. The sample also demonstrates how a REF Cursor can be updated.
+* Sample 5: Demonstrates how a DataSet can be populated from an OracleRefCursor object.
+* Sample 6: Demonstrates how to populate a DataSet with multiple REF Cursors selectively.
+* Sample 7: Demonstrates how to selectively obtain OracleDataReader objects from REF Cursors. + +Statement Cache +--------------- +* Sample 1: Demonstrates performance improvement when statement caching is enabled. + +Transaction +----------- +* Sample 1: Demonstrates the usage of EnlistTransaction API.
+* Sample 2: Demonstrates the usage of TransactionScope.
+* Sample 3: Demonstrates nested transactions with savepoints. + +User-Defined Types (UDT) +------------------------ +* Nested Table Sample: Demonstrates how to map, fetch, and manipulate a nested table of UDTs that has an inheritance hierarchy (i.e. parent and child types).
+* Object UDT Sample: Demonstrates how to map, fetch, and manipulate an Oracle UDT as a .NET custom object.
+* Spatial UDT Sample: Demonstrates how to map and fetch types similar to Oracle Spatial types as custom types.
+* Ref Sample: Demonstrates how to fetch UDTs referenced by REFs.
+* Ref Inheritance Sample: Demonstrates how to obtain and update Custom Type objects from OracleRef objects.
+* VARRAY Sample: Demonstrates how to map, fetch, and manipulate the Oracle VARRAY as a custom object. + diff --git a/samples/README.txt b/samples/README.txt deleted file mode 100644 index 3220510d..00000000 --- a/samples/README.txt +++ /dev/null @@ -1,118 +0,0 @@ -ODP.NET, Managed Driver Code Samples -==================================== -You must have managed ODP.NET installed. To run the samples, follow these directions: -1) Modify the Data Source attribute in the connection strings to connect to an Oracle database via Easy Connect, TNS connect descriptor, or TNS alias. -2) Most of these samples use the SCOTT schema. The create scripts for SCOTT schema are located here: https://github.com/oracle/dotnet-db-samples/tree/master/schemas -3) Add Oracle.ManagedDataAccess.dll to the sample application. -4) Read \doc\Readme.html, if any. - -While these samples are designed for managed ODP.NET, they can use unmanaged ODP.NET by incorporating Oracle.DataAccess.dll and adding the correct namespace references (i.e. using Oracle.DataAccess.Client; using Oracle.DataAccess.Types;). - -Below is a list of topics that the samples cover: - -Application Continuity -====================== -Sample 1: Unmanaged ODP.NET Application Continuity code sample with setup and runtime demo instructions. - -Parameter Array Binding -======================= -Sample 1: Demonstrates parameter array binding. - -PL/SQL Associative Array -======================== -Sample 1: Demonstrates PL/SQL Associative Array binding. - -Autonomous Database -=================== -Sample 1: Demonstrates how to connect managed ODP.NET to Oracle Autonomous Database. -Sample 2: Demonstrates how to connect unmanaged ODP.NET to Oracle Autonomous Database. -Sample 3: Demonstrates how to connect ODP.NET Core to Oracle Autonomous Database. The sample is located in the .NET Core subdirectory. - -Client Factory -============== -Sample 1: Demonstrates how to use the OracleClientFactory class. - -Command Builder -=============== -Sample 1: Demonstrates OracleCommandBuilder's SchemaSeparator property. -Sample 2: Demonstrates OracleCommandBuilders's QuoteIdentifier method. -Sample 3: Demonstrates OracleCommandBuilders's UnquoteIdentifier method. - -Connection -========== -Sample 1: Demonstrates OracleConnection's GetSchema() method. -Sample 2: Demonstrates all variations of OracleConnection's GetSchema(string) method overload. -Sample 3: Demonstrates all variations of OracleConnection's GetSchema(string, string[]) method overload. - -Connection String Builder -========================= -Sample 1: Demonstrates how to use the OracleConnectionStringBuilder class. - -Data Reader -=========== -Sample 1: Demonstrates OracleDataReader's VisibleFieldCount and HiddenFieldCount properties. - -Data Source Enumerator -====================== -Sample 1: Demonstrates the functionality of OracleDataSourceEnumerator class. - -DataSet -======= -Sample 1: Demonstrates data manipulation language (DML) operations on a Dataset. -Sample 2: Demonstrates how to populate a DataSet using C#. -Sample 3: Demonstrates DML operations on LOB columns. -Sample 4: Demonstrates how to populate a DataSet from multiple output Ref Cursors from a stored procedure. -Sample 5: Demonstrates how to populate a DataSet using Visual Basic .NET (VB.NET). - -.NET Core -========= -ASP.NET Core Sample: Demonstrates a simple ASP.NET Core web app to connect and retrieve data -Data Reader Sample: Demonstrates how to connect and retrieve data using ODP.NET Core via a console app -Configuration API Sample: Demonstrates how to use the OracleConfiguration, OracleDataSourceCollection, and OracleOnsServerCollection classes. -Autonomous DB Sample: Demonstrates how to connect ODP.NET Core to Oracle Autonomous Database. -Entity Framework Core Sample: Demonstrates Oracle EF Core using DB First and scaffolding scenarios. - - -Event Handler -============= -Sample 1: Demonstrates how to trap the OracleRowUpdatingEvent and OracleRowUpdatedEvent using VB.NET. - -JSON -==== -Select JSON Sample: Demonstrates row insert into and query against a JSON table. -Select JSON CLOB Sample: Demonstrates row insert into and query against a JSON table using CLOB storage. - -LOB -=== -Sample 1: Demonstrates how to populate and obtain LOB data from a DataSet. -Sample 2: Demonstrates how an OracleClob object is obtained as an output parameter of an anonymous PL/SQL block. -Sample 3: Demonstrates how an OracleClob object is obtained from an output parameter of a stored procedure. -Sample 4: Demonstrates how the LOB column data can be read as a .NET type by utilizing stream reads. -Sample 5: Demonstrates how to bind an OracleClob object as a parameter. This sample also refetches the newly updated CLOB data using an OracleDataReader and an OracleClob object. -Sample 6: Demonstrates LOB updates using row-level locking. -Sample 7: Demonstrates LOB updates using result set locking. -BFile Sample: Demonstrates accessing BFILEs through ODP.NET. - -Performance Counters -==================== -Sample 1: Demonstrates how to programmatically use ODP.NET performance counters. - -Ref Cursor -========== -Sample 1: Demonstrates how a REF Cursor is obtained as an OracleDataReader. -Sample 2: Demonstrates how a REF Cursor is obtained as an OracleDataReader through the use of an OracleRefCursor object. -Sample 3: Demonstrates how multiple REF Cursors can be accessed by a single OracleDataReader. -Sample 4: Demonstrates how a DataSet can be populated from a REF Cursor. The sample also demonstrates how a REF Cursor can be updated. -Sample 5: Demonstrates how a DataSet can be populated from an OracleRefCursor object. -Sample 6: Demonstrates how to populate a DataSet with multiple REF Cursors selectively. -Sample 7: Demonstrates how to selectively obtain OracleDataReader objects from REF Cursors. - -Statement Cache -=============== -Sample 1: Demonstrates performance improvement when statement caching is enabled. - -Transaction -=========== -Sample 1: Demonstrates the usage of EnlistTransaction API. -Sample 2: Demonstrates the usage of TransactionScope. -Sample 3: Demonstrates nested transactions with savepoints. diff --git a/samples/ai-vector/Ai-vector-search-stores-and-collections.cs b/samples/ai-vector/Ai-vector-search-stores-and-collections.cs new file mode 100644 index 00000000..5a79af21 --- /dev/null +++ b/samples/ai-vector/Ai-vector-search-stores-and-collections.cs @@ -0,0 +1,192 @@ +using Oracle.VectorData; +using Oracle.ManagedDataAccess.Client; +using Microsoft.Extensions.VectorData; +using Microsoft.Extensions.Configuration; +using System.Text.Json; + +namespace OracleAIVectorData; + +// This ODP.NET sample app shows various ways to search vector data and collections. +// First, the data (hotels.json) is loaded into a .NET object list. +// The data initially includes hotel names, descriptions, ids, ratings, and parking availability. +// The hotel names and descriptions are then vectorized using the database ONNX embeddings, consisting of 384 dimensions in Float format. +// The entire data set is upserted into the database. +// Finally, four search operations are demonstrated. +// 1. Search by primary key. +// 2. Search scalar value properties. +// 3. Similarity search using cosine similarity. +// 4. Similarity search using Euclidean distance. +// This sample requires Oracle Database 23ai or higher. +// Add Oracle.VectorData and Microsoft.Extensions.Configuration.Json NuGet packages to your project. + +public class AIHotelSearchApp +{ + public static async Task Main(string[] args) + { + await SearchHotels(); + } + static async Task SearchHotels() + { + // Setup ODP.NET connection and vector configuration. + // Set connection string values in AppSettings.json file. + // Add AppSettings.json directory path below or place file in app's output directory. + var configuration = new ConfigurationBuilder() + .AddJsonFile(path: "AppSettings.json", optional: false) + .Build(); + + string? connStr = configuration.GetSection("Oracle")["ConnectionString"]; + OracleDataSource? ds = null; + OracleVectorStore? vs = null; + OracleCollection? collection = null; + string collectionName = "Hotels"; + + try + { + ds = new OracleDataSourceBuilder(connStr).Build(); + + // Create a vector store + vs = new OracleVectorStore(ds); + + // Create a vector collection + collection = (OracleCollection)vs.GetCollection(collectionName); + + // HotelsData.json contains plain text information about various hotels. + // Add Hotels.json directory path below or place file in app's output directory. + string jsonContent = File.ReadAllText("Hotels.json"); + List? hotels = JsonSerializer.Deserialize>(jsonContent); + + // Use the database ONNX generator to create VECTOR(384, FLOAT32) embeddings for each hotel/record. + foreach (Hotel hotel in hotels) + { + hotel.NameEmbedding = await GenerateEmbeddingAsync(ds, hotel.HotelName); + hotel.DescriptionEmbedding = await GenerateEmbeddingAsync(ds, hotel.Description); + } + + // Verify the collection exists in the database. + await collection.EnsureCollectionExistsAsync(); + + // Upsert the records into the database. + await collection.UpsertAsync(hotels); + + // Search hotels in the vector collection by primary key. + Console.WriteLine("Search for hotels with ID 5 and 10."); + Console.WriteLine("==============================================================================="); + IAsyncEnumerable hotelsById = collection.GetAsync([5, 10]); + await foreach (Hotel hotel in hotelsById) + { + Output(hotel); + } + Console.WriteLine(); + + // Search hotels by their characteristics, such as rating and parking availability. + Console.WriteLine("Search for hotels with a 9 or higher rating and parking."); + Console.WriteLine("==============================================================================="); + IAsyncEnumerable hotelsByFilter2 = collection.GetAsync(r => r.Rating >= 9 && r.HasParking == true, 3); + await foreach (Hotel hotel in hotelsByFilter2) + { + Output(hotel); + } + Console.WriteLine(); + + // Search hotels by their names. Return top three most similar matches. + // Provide a search term, such as "beach". Generate a vector embedding using the search term. + // ODP.NET performs a similarity search using the hotel name and search term embeddings. + // The cosine similarity metric is used to calculate vector distances to find the best matches. + // Scores closer to zero are more similar. Higher scores mean more dissimilarity. + // Results are ranked from most similar to least. + string hotelNameSearchStr = "beach"; + + var nameEmbedding = await GenerateEmbeddingAsync(ds, hotelNameSearchStr); + // Specify the search option for hotel name. + VectorSearchOptions nameOptions = new() { VectorProperty = r => r.NameEmbedding }; + IAsyncEnumerable> namesVectorSearch = collection.SearchAsync(nameEmbedding, top: 3, nameOptions); + + int rank = 1; + Console.WriteLine($"Hotel name similarity search with \"{hotelNameSearchStr}\"."); + Console.WriteLine("==============================================================================="); + await foreach (VectorSearchResult searchResult in namesVectorSearch) + { + Console.WriteLine(rank + $". {searchResult.Record.HotelName}"); + Console.WriteLine($"Score : {searchResult.Score}"); + Console.WriteLine(); + rank++; + } + Console.WriteLine(); + + // Search hotels using their descriptions. Return top three most similar matches. + // Provide a search phrase or sentence. Generate its vector embedding. + // ODP.NET performs a similarity search using the hotel description and search text embeddings. + // The Euclidean distance metric is used to calculate vector distances to find the best matches. + string descriptionSearchStr = "I want a hotel with nature activities."; + var descriptionEmbedding = await GenerateEmbeddingAsync(ds, descriptionSearchStr); + + // Specify the search option for hotel description. + VectorSearchOptions descriptionOptions = new() { VectorProperty = r => r.DescriptionEmbedding }; + IAsyncEnumerable> descriptionVectorSearch = collection.SearchAsync(descriptionEmbedding, top: 3, descriptionOptions); + + rank = 1; + Console.WriteLine($"Hotel description similarity search with \"{descriptionSearchStr}\"."); + Console.WriteLine("==============================================================================="); + await foreach (VectorSearchResult searchResult in descriptionVectorSearch) + { + Console.WriteLine(rank + $". {searchResult.Record.HotelName}"); + Console.WriteLine($"Score : {searchResult.Score}"); + Console.WriteLine($"Description: {searchResult.Record.Description}"); + Console.WriteLine(); + rank++; + } + } + + finally + { + // Clean up and delete the collection + if (vs != null) { await vs.EnsureCollectionDeletedAsync(collectionName); } + ds?.Dispose(); + vs?.Dispose(); + collection?.Dispose(); + } + } + + // Generate embeddings in ONNX format. + // This app uses Hugging Face's all-MiniLM-L12-v2 model for all its embeddings. + static async Task GenerateEmbeddingAsync(OracleDataSource ds, string searchText, CancellationToken cancellationtoken = default) + { + using (OracleConnection conn = await ds.OpenConnectionAsync(cancellationtoken)) + { + using (OracleCommand cmd = new OracleCommand($"SELECT TO_VECTOR(VECTOR_EMBEDDING(ALL_MINILM_L12_V2 USING :1 as DATA), 384, FLOAT32)", conn)) + { + cmd.Parameters.Add("searchStr", OracleDbType.Varchar2, null, System.Data.ParameterDirection.Input); + cmd.Parameters[0].Value = searchText; + return (float[])cmd.ExecuteScalar(); + } + } + } + + // Output the hotel's information to the console. + static void Output(Hotel hotel) + { + Console.WriteLine($"Hotel Name = {hotel.HotelName}"); + Console.WriteLine($"Hotel Id = {hotel.HotelId}"); + Console.WriteLine($"Rating = {hotel.Rating}"); + Console.WriteLine($"HasParking = {hotel.HasParking}"); + Console.WriteLine(); + } +} +/* Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ \ No newline at end of file diff --git a/samples/ai-vector/AppSettings.json b/samples/ai-vector/AppSettings.json new file mode 100644 index 00000000..aef4274b --- /dev/null +++ b/samples/ai-vector/AppSettings.json @@ -0,0 +1,5 @@ +{ + "Oracle": { + "ConnectionString": "User Id=ADMIN; Password=; Data Source=;" + } +} \ No newline at end of file diff --git a/samples/ai-vector/Hotel.cs b/samples/ai-vector/Hotel.cs new file mode 100644 index 00000000..1ff94d3a --- /dev/null +++ b/samples/ai-vector/Hotel.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.VectorData; + +namespace OracleAIVectorData +{ + public class Hotel + { + [VectorStoreKey] + public int HotelId { get; set; } + + [VectorStoreData] + public string HotelName { get; set; } + + [VectorStoreData] + public float Rating { get; set; } + + [VectorStoreData] + public bool HasParking { get; set; } + + [VectorStoreData] + public string Description { get; set; } + + //Oracle has numerous vector distance functions to identify the most relevant results. + //Let's use cosine similarity for the hotel name vectors. + [VectorStoreVector(Dimensions: 384, DistanceFunction = DistanceFunction.CosineDistance)] + public float[] NameEmbedding { get; set; } + + //Let's use Euclidean distance for the hotel description vectors. + [VectorStoreVector(Dimensions: 384, DistanceFunction = DistanceFunction.EuclideanDistance)] + public float[] DescriptionEmbedding { get; set; } + } +} +/* Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ \ No newline at end of file diff --git a/samples/ai-vector/Hotels.json b/samples/ai-vector/Hotels.json new file mode 100644 index 00000000..452610df --- /dev/null +++ b/samples/ai-vector/Hotels.json @@ -0,0 +1,142 @@ +[ + { + "HotelName": "The Lodge by the Sea", + "Description": "A legendary beach hotel with beautiful sunsets, outdoor activites, and near top restaurants.", + "HotelId": 1, + "Rating": 9.5, + "HasParking": true + }, + { + "HotelName": "Hotel New York", + "Description": "An urban retreat in the heart of New York City known for its skyline views and well-appointed rooms.", + "HotelId": 2, + "Rating": 8, + "HasParking": false + }, + { + "HotelName": "Maui Island Retreat", + "Description": "A luxury Maui beach resort with environmentally sustainable design and privacy.", + "HotelId": 3, + "Rating": 3, + "HasParking": true + }, + { + "HotelName": "Hotel San Francisco", + "Description": "A historic hotel in the middle of downtown with modern elegance and legendary service.", + "HotelId": 4, + "Rating": 7.9, + "HasParking": false + }, + { + "HotelName": "The Mountain Lake Resort", + "Description": "A wellness retreat set in the Swiss Alps, offering spa, yoga, and cross-country skiing in tranquil surroundings.", + "HotelId": 5, + "Rating": 7, + "HasParking": true + }, + { + "HotelName": "The Standard", + "Description": "Palace-level luxury in London, famed for gourmet dining and the epitome of service.floral lobbies.", + "HotelId": 6, + "Rating": 6.2, + "HasParking": false + }, + { + "HotelName": "Desert Dream", + "Description": "An oasis of luxury for relaxation and fine dining.", + "HotelId": 7, + "Rating": 8, + "HasParking": true + }, + { + "HotelName": "The Cottages by the Lake", + "Description": "Countryside luxury, blending warm design, personal attention, and water activites.", + "HotelId": 8, + "Rating": 5, + "HasParking": false + }, + { + "HotelName": "The Paris", + "Description": "Historic hotel emblematic of French refinement, dining, and service.", + "HotelId": 9, + "Rating": 3.8, + "HasParking": true + }, + { + "HotelName": "Marina Hotel", + "Description": "A sanctuary for sailing enthusiasts on the beach.", + "HotelId": 10, + "Rating": 6, + "HasParking": false + }, + { + "HotelName": "The Grand Hotel", + "Description": "Iconic Tokyo landmark offering classic luxury and a celebrated history next to the city business center.", + "HotelId": 11, + "Rating": 10, + "HasParking": true + }, + { + "HotelName": "The Cabins", + "Description": "Located at the edge of a large forest. Perfect for hiking and exploring.", + "HotelId": 12, + "Rating": 5.5, + "HasParking": false + }, + { + "HotelName": "Botique Hotel", + "Description": "A chateau-hotel in wine country surrounded by the serene beauty of the nature.", + "HotelId": 13, + "Rating": 2, + "HasParking": true + }, + { + "HotelName": "Business Hotel", + "Description": "For the executive wanting to maximize productivity with minimal distractions.", + "HotelId": 14, + "Rating": 4.9, + "HasParking": false + }, + { + "HotelName": "The Country Motel", + "Description": "An affordable hotel in the outskirts of town with basic services and nearby trails.", + "HotelId": 15, + "Rating": 1, + "HasParking": true + }, + { + "HotelName": "The HK", + "Description": "Iconic urban hotel in Hong Kong with harbor views and banquet dining.", + "HotelId": 16, + "Rating": 8.1, + "HasParking": false + }, + { + "HotelName": "The Nature Inn", + "Description": "Located by a river in the hills, this hotel offers rooms with private terraces and stunning views.", + "HotelId": 17, + "Rating": 2.5, + "HasParking": true + }, + { + "HotelName": "Casino Hotel", + "Description": "Elegance, renowed entertainment, and the largest choice of games on the Las Vegas strip.", + "HotelId": 18, + "Rating": 7.3, + "HasParking": false + }, + { + "HotelName": "The Island Hotel", + "Description": "Located in the South Pacific, this luxurious resort has beach and water activities.", + "HotelId": 19, + "Rating": 4, + "HasParking": true + }, + { + "HotelName": "The Healthy Inn", + "Description": "A renowned wellness resort in California, offering holistic health programs and yoga.", + "HotelId": 20, + "Rating": 3.2, + "HasParking": false + } +] \ No newline at end of file diff --git a/samples/ai-vector/Load-model.sql b/samples/ai-vector/Load-model.sql new file mode 100644 index 00000000..d24463eb --- /dev/null +++ b/samples/ai-vector/Load-model.sql @@ -0,0 +1,56 @@ +DECLARE + ONNX_MOD_FILE VARCHAR2(100) := 'all_MiniLM_L12_v2.onnx'; + MODNAME VARCHAR2(500); + LOCATION_URI VARCHAR2(200) := 'https://adwc4pm.objectstorage.us-ashburn-1.oci.customer-oci.com/p/eLddQappgBJ7jNi6Guz9m9LOtYe2u8LWY19GfgU8flFK4N9YgP4kTlrE9Px3pE12/n/adwc4pm/b/OML-Resources/o/'; + +BEGIN + DBMS_OUTPUT.PUT_LINE('ONNX model file name in object storage is: '||ONNX_MOD_FILE); +-------------------------------------------- +-- Define a model name for the loaded model +-------------------------------------------- + SELECT UPPER(REGEXP_SUBSTR(ONNX_MOD_FILE, '[^.]+')) INTO MODNAME from dual; + DBMS_OUTPUT.PUT_LINE('Model will be loaded and saved with name: '||MODNAME); + +----------------------------------------------------- +-- Read the ONNX model file from object storage into +-- the Autonomous Database data pump directory +----------------------------------------------------- + +BEGIN DBMS_DATA_MINING.DROP_MODEL(model_name => MODNAME); +EXCEPTION WHEN OTHERS THEN NULL; END; + + DBMS_CLOUD.GET_OBJECT( + credential_name => NULL, + directory_name => 'DATA_PUMP_DIR', + object_uri => LOCATION_URI||ONNX_MOD_FILE); + +----------------------------------------- +-- Load the ONNX model to the database +----------------------------------------- + + DBMS_VECTOR.LOAD_ONNX_MODEL( + directory => 'DATA_PUMP_DIR', + file_name => ONNX_MOD_FILE, + model_name => MODNAME); + + DBMS_OUTPUT.PUT_LINE('New model successfully loaded with name: '||MODNAME); +END; + +/* Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ \ No newline at end of file diff --git a/samples/ai-vector/Oracle AI Vector Data.csproj b/samples/ai-vector/Oracle AI Vector Data.csproj new file mode 100644 index 00000000..b5da0f8c --- /dev/null +++ b/samples/ai-vector/Oracle AI Vector Data.csproj @@ -0,0 +1,25 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + diff --git a/samples/application-continuity/AppContinuity.cs b/samples/application-continuity/AppContinuity.cs index 2e08b063..f1f94e2f 100644 --- a/samples/application-continuity/AppContinuity.cs +++ b/samples/application-continuity/AppContinuity.cs @@ -1,26 +1,8 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using System.Threading; using System.Transactions; -using Oracle.DataAccess.Client; +//using Oracle.DataAccess.Client; +using Oracle.ManagedDataAccess.Client; namespace AppContinuity { @@ -51,7 +33,9 @@ static void Main(string[] args) // B) In client app, modify the following connection attributes in this sample code: // 1) Password: Password you specified while setting up HR schema setup. // 2) Data Source: Connection descriptor or TNS alias to connect to the database. - // Be sure to use unmanaged ODP.NET 12.2 or higher, which supports AC. + // 3) Use the Oracle.ManagedDataAccess.Client namespace for managed ODP.NET or ODP.NET Core. + // Or use Oracle.Data.Client namespace for unmanaged ODP.NET. + // Be sure to use a minimum version of ODP.NET Core 23c, managed ODP.NET 23c, or unmanaged ODP.NET 12.2 for AC support. //Runtime instructions: // You can intermittently execute the following command on the database @@ -102,3 +86,22 @@ static void Main(string[] args) } } } + +/* Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/array-bind/ArrayBind.cs b/samples/array-bind/ArrayBind.cs index edb9e7ca..e2eca90f 100644 --- a/samples/array-bind/ArrayBind.cs +++ b/samples/array-bind/ArrayBind.cs @@ -1,12 +1,115 @@ -/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ - +using System; +using System.Data; +using Oracle.ManagedDataAccess.Client; + +namespace ODPArrayBind +{ + /// + /// Sample: Demonstrates ODP.NET array binding + /// + class ArrayBind + { + static void Main(string[] args) + { + // Connect + // This sample code's DEPT table shares the same characteristics as the SCOTT schema's DEPT table. + string connectStr = "User Id=;Password=;Data Source="; + + // Clear rows from past sample code executions + Setup(connectStr); + + // Initialize array of data + int[] myArrayDeptNo = new int[4] { 1, 2, 3, 4 }; + String[] myArrayDeptName = { "Dev", "QA", "PM", "Integration" }; + String[] myArrayDeptLoc = { "California", "Arizona", "Texas", "Oregon" }; + + OracleConnection connection = new OracleConnection(connectStr); + OracleCommand command = new OracleCommand( + "insert into dept values (:deptno, :deptname, :loc)", connection); + + // Set the array size to 4. This applies to all the command's associated parameters. + command.ArrayBindCount = 4; + + // Deptno parameter + OracleParameter deptNoParam = new OracleParameter("deptno", OracleDbType.Int32); + deptNoParam.Direction = ParameterDirection.Input; + deptNoParam.Value = myArrayDeptNo; + command.Parameters.Add(deptNoParam); + + // Deptname parameter + OracleParameter deptNameParam = new OracleParameter("deptname", OracleDbType.Varchar2); + deptNameParam.Direction = ParameterDirection.Input; + deptNameParam.Value = myArrayDeptName; + command.Parameters.Add(deptNameParam); + + // Loc parameter + OracleParameter deptLocParam = new OracleParameter("loc", OracleDbType.Varchar2); + deptLocParam.Direction = ParameterDirection.Input; + deptLocParam.Value = myArrayDeptLoc; + command.Parameters.Add(deptLocParam); + + try + { + connection.Open(); + command.ExecuteNonQuery(); + Console.WriteLine("{0} rows inserted", command.ArrayBindCount); + } + catch (Exception e) + { + Console.WriteLine("Execution failed:" + e.Message); + } + finally + { + // Dispose connection and command used server side resource + connection.Close(); + command.Dispose(); + connection.Dispose(); + } + } + + public static void Setup(string connectStr) + { + int[] myArrayDeptNo = new int[4] { 1, 2, 3, 4 }; + + OracleConnection conn = new OracleConnection(connectStr); + OracleCommand cmd = new OracleCommand("delete dept where deptno = :1", conn); + + // Bind with a 4 item array + cmd.ArrayBindCount = 4; + + OracleParameter param1 = new OracleParameter(); + param1.OracleDbType = OracleDbType.Int32; + param1.Value = myArrayDeptNo; + + cmd.Parameters.Add(param1); + + try + { + conn.Open(); + cmd.ExecuteNonQuery(); + } + catch (Exception e) + { + Console.WriteLine("Setup Failed:{0}", e.Message); + } + finally + { + conn.Close(); + cmd.Dispose(); + } + } + } +} + +/* Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. */ + /****************************************************************************** * * You may not use the identified files except in compliance with The MIT * License (the "License.") * * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT @@ -16,108 +119,3 @@ * limitations under the License. * *****************************************************************************/ - -using System; -using System.Data; -using Oracle.ManagedDataAccess.Client; - -namespace ODPSample -{ - /// - /// Sample: Demonstrates array binding - /// - class ArrayBind - { - static void Main(string[] args) - { - // Connect - // This sample code's DEPT table shares the same characteristics as SCOTT schema's DEPT table - string connectStr = "User Id=;Password=;Data Source="; - - // Setup the Tables for sample - Setup(connectStr); - - // Initialize array of data - int[] myArrayDeptNo = new int[3]{1, 2, 3}; - String[] myArrayDeptName = {"Dev", "QA", "Facility"}; - String[] myArrayDeptLoc = {"New York", "Maryland", "Texas"}; - - OracleConnection connection = new OracleConnection(connectStr); - OracleCommand command = new OracleCommand ( - "insert into dept values (:deptno, :deptname, :loc)", connection); - - // Set the Array Size to 3. This applied to all the parameter in - // associated with this command - command.ArrayBindCount = 3; - - // deptno parameter - OracleParameter deptNoParam = new OracleParameter("deptno",OracleDbType.Int32); - deptNoParam.Direction = ParameterDirection.Input; - deptNoParam.Value = myArrayDeptNo; - command.Parameters.Add(deptNoParam); - - // deptname parameter - OracleParameter deptNameParam = new OracleParameter("deptname", OracleDbType.Varchar2); - deptNameParam.Direction = ParameterDirection.Input; - deptNameParam.Value = myArrayDeptName; - command.Parameters.Add(deptNameParam); - - // loc parameter - OracleParameter deptLocParam = new OracleParameter("loc", OracleDbType.Varchar2); - deptLocParam.Direction = ParameterDirection.Input; - deptLocParam.Value = myArrayDeptLoc; - command.Parameters.Add(deptLocParam); - - try - { - connection.Open(); - command.ExecuteNonQuery(); - Console.WriteLine("{0} Rows Inserted", command.ArrayBindCount); - } - catch (Exception e) - { - Console.WriteLine("Execution Failed:" + e.Message); - } - finally - { - // connection, command used server side resource, dispose them - // asap to conserve resource - connection.Close(); - command.Dispose(); - connection.Dispose(); - } - } - - public static void Setup(string connectStr) - { - int[] myArrayDeptNo = new int[3]{1, 2, 3}; - - OracleConnection conn = new OracleConnection(connectStr); - OracleCommand cmd = new OracleCommand("delete dept where deptno = :1", conn); - - // Bind with an array of 3 items - cmd.ArrayBindCount = 3; - - OracleParameter param1 = new OracleParameter(); - param1.OracleDbType = OracleDbType.Int32; - param1.Value = myArrayDeptNo; - - cmd.Parameters.Add(param1); - - try - { - conn.Open(); - cmd.ExecuteNonQuery(); - } - catch (Exception e) - { - Console.WriteLine("Setup Failed:{0}" ,e.Message); - } - finally - { - conn.Close(); - cmd.Dispose(); - } - } - } -} diff --git a/samples/array-bind/ArrayBind.csproj b/samples/array-bind/ArrayBind.csproj deleted file mode 100644 index 0ac9e7da..00000000 --- a/samples/array-bind/ArrayBind.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {783CC13A-4660-494A-8025-DEF68921B27F} - Debug - AnyCPU - - - - - ArrayBind - v4.0 - - - JScript - Grid - IE50 - false - Exe - ODPSample - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/dotnet-core/asp.net-core/2.x/Program.cs b/samples/asp.net-core/2.x/Program.cs similarity index 99% rename from samples/dotnet-core/asp.net-core/2.x/Program.cs rename to samples/asp.net-core/2.x/Program.cs index 901df1ec..8c9a1820 100644 --- a/samples/dotnet-core/asp.net-core/2.x/Program.cs +++ b/samples/asp.net-core/2.x/Program.cs @@ -1,21 +1,3 @@ -/* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ using System; using System.Collections.Generic; using System.IO; @@ -41,3 +23,22 @@ public static IWebHost BuildWebHost(string[] args) => .Build(); } } + +/* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/asp.net-core/2.x/Startup.cs b/samples/asp.net-core/2.x/Startup.cs similarity index 100% rename from samples/dotnet-core/asp.net-core/2.x/Startup.cs rename to samples/asp.net-core/2.x/Startup.cs index 5d616bfd..89785bbf 100644 --- a/samples/dotnet-core/asp.net-core/2.x/Startup.cs +++ b/samples/asp.net-core/2.x/Startup.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using System.Collections.Generic; using System.Linq; @@ -98,3 +79,22 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) } } } + +/* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/asp.net-core/3.x/Program.cs b/samples/asp.net-core/3.x/Program.cs similarity index 100% rename from samples/dotnet-core/asp.net-core/3.x/Program.cs rename to samples/asp.net-core/3.x/Program.cs diff --git a/samples/dotnet-core/asp.net-core/3.x/Startup.cs b/samples/asp.net-core/3.x/Startup.cs similarity index 100% rename from samples/dotnet-core/asp.net-core/3.x/Startup.cs rename to samples/asp.net-core/3.x/Startup.cs diff --git a/samples/asp.net-core/6/Program.cs b/samples/asp.net-core/6/Program.cs new file mode 100644 index 00000000..92f16a14 --- /dev/null +++ b/samples/asp.net-core/6/Program.cs @@ -0,0 +1,61 @@ +using Oracle.ManagedDataAccess.Client; + +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.MapGet("/", async (context) => +{ + //Set the user id, password and data source + //Set Data Source value to Oracle connect descriptor or net service name + string conString = "User Id=HR;Password=;Data Source=;"; + using (OracleConnection con = new OracleConnection(conString)) + { + using (OracleCommand cmd = con.CreateCommand()) + { + try + { + con.Open(); + + //Use the command to display employee names from EMPLOYEES table + cmd.CommandText = "select first_name, last_name from employees where department_id = :id"; + + // Assign id to the department number 50 + cmd.BindByName = true; + OracleParameter id = new OracleParameter("id", 50); + cmd.Parameters.Add(id); + + OracleDataReader reader = cmd.ExecuteReader(); + while (reader.Read()) + await context.Response.WriteAsync("Employee Name: " + reader.GetString(0) + " " + reader.GetString(1) + "\n"); + + id.Dispose(); + reader.Dispose(); + } + catch (Exception ex) + { + await context.Response.WriteAsync(ex.Message); + } + } + } +}); + +app.Run(); + +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/assoc-array/AssocArray.cs b/samples/assoc-array/AssocArray.cs index e9dd9e66..216c5655 100644 --- a/samples/assoc-array/AssocArray.cs +++ b/samples/assoc-array/AssocArray.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using System.Data; using System.Text; @@ -187,3 +168,22 @@ public static void Display(OracleParameterCollection collection) } } } + +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/assoc-array/AssocArray.csproj b/samples/assoc-array/AssocArray.csproj deleted file mode 100644 index e0e82a20..00000000 --- a/samples/assoc-array/AssocArray.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {09F9CB68-8BCE-47CA-868A-8430EA74B480} - Debug - AnyCPU - - - - - AssocArray - v4.0 - - - JScript - Grid - IE50 - false - Exe - ODPSample - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/async/async.cs b/samples/async/async.cs new file mode 100644 index 00000000..33437f11 --- /dev/null +++ b/samples/async/async.cs @@ -0,0 +1,70 @@ +using Oracle.ManagedDataAccess.Client; +using System.Threading.Tasks; +using System.Threading; +using System; + +// This app uses asynchronous ODP.NET (managed or core) APIs to open a connection, +// execute a SQL statement, and read the results. It times how long these operations take. +// To run this app, add your database's HR schema User Id, Password, and Data Source values +// with ODP.NET 23ai or higher connecting to an Oracle Database 19c or higher. + +class ODPNET_Async +{ + public static async Task Main() + { + // Add password and data source to connect to your Oracle database + string conString = "User Id=hr;Password=;Data Source=;"; + + using (OracleConnection con = new OracleConnection(conString)) + { + //Time how long it takes to open a connection asynchronously + DateTime start_time = DateTime.Now; + Task task = con.OpenAsync(); + DateTime end_time_open = DateTime.Now; + + // Simulate operation that takes one second + Thread.Sleep(1000); + + string cmdText = "SELECT * FROM EMPLOYEES FETCH FIRST 100 ROWS ONLY"; + using (OracleCommand cmd = new OracleCommand(cmdText, con)) + { + // Retrieve open connection + await task; + using (OracleDataReader reader = await cmd.ExecuteReaderAsync()) + { + await reader.ReadAsync(); + } + } + DateTime end_time_all = DateTime.Now; + + // Calculate connection open time + TimeSpan ts_open = end_time_open - start_time; + double ts_open1 = Math.Round(ts_open.TotalSeconds, 2); + Console.WriteLine("Asynchronous connection open time: " + ts_open1 + " seconds"); + + // Calculate overall ODP.NET operation time + TimeSpan ts_all = end_time_all - start_time; + double ts_all1 = Math.Round(ts_all.TotalSeconds, 2); + Console.WriteLine("Asynchronous ODP.NET overall time: " + ts_all1 + " seconds"); + } + } +} + +/* Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/async/sync.cs b/samples/async/sync.cs new file mode 100644 index 00000000..165ba0f5 --- /dev/null +++ b/samples/async/sync.cs @@ -0,0 +1,69 @@ +using Oracle.ManagedDataAccess.Client; +using System.Threading.Tasks; +using System.Threading; +using System; + +// This app uses synchronous ODP.NET (managed or core) APIs to open a connection, +// execute a SQL statement, and read the results. It times how long these operations take. +// To run this app, add your database's HR schema User Id, Password, and Data Source values +// with ODP.NET 23ai or higher connecting to an Oracle Database 19c or higher. + + +class ODPNET_Sync +{ + static void Main() + { + // Add password and data source to connect to your Oracle database + string conString = "User Id=hr;Password=;Data Source=;"; + + using (OracleConnection con = new OracleConnection(conString)) + { + //Time how long it takes to open a connection + DateTime start_time = DateTime.Now; + con.Open(); + DateTime end_time_open = DateTime.Now; + + // Simulate operation that takes one second + Thread.Sleep(1000); + + string cmdText = "SELECT * FROM EMPLOYEES FETCH FIRST 100 ROWS ONLY"; + using (OracleCommand cmd = new OracleCommand(cmdText, con)) + { + using (OracleDataReader reader = cmd.ExecuteReader()) + { + reader.Read(); + } + } + DateTime end_time_all = DateTime.Now; + + // Calculate connection open time + TimeSpan ts_open = end_time_open - start_time; + double ts_open1 = Math.Round(ts_open.TotalSeconds, 2); + Console.WriteLine("Synchronous connection open time: " + ts_open1 + " seconds"); + + // Calculate overall ODP.NET operation time + TimeSpan ts_all = end_time_all - start_time; + double ts_all1 = Math.Round(ts_all.TotalSeconds, 2); + Console.WriteLine("Synchronous ODP.NET overall time: " + ts_all1 + " seconds"); + } + } +} + +/* Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/autonomous-db/README.md b/samples/autonomous-db/README.md index 63cf3e95..6ef122dc 100644 --- a/samples/autonomous-db/README.md +++ b/samples/autonomous-db/README.md @@ -1,8 +1,8 @@ -These ODP.NET Autonomous Database code samples are intended to be used with the [Developing .NET Framework Applications for Oracle Autonomous Database tutorial](https://www.oracle.com/database/technologies/appdev/dotnet/adbdotnetfw.html). +These ODP.NET Autonomous Database code samples are intended to be used with the Developing .NET Applications for Oracle Autonomous Database quick starts. +* [ODP.NET Core for ADB Quick Start](https://www.oracle.com/database/technologies/appdev/dotnet/adbdotnetquickstarts.html) +* [Managed ODP.NET for ADB Quick Start](https://www.oracle.com/database/technologies/appdev/dotnet/adbdotnetquickstarts.html#fourth-option-tab) +* [Unmanaged ODP.NET for ADB Quick Start](https://www.oracle.com/database/technologies/appdev/dotnet/adbdotnetfw.html) -This sample demonstrates how to connect to Oracle Autonomous Database, including Oracle Autonomous Transaction Processing and Autonomous Data Warehouse. +These samples demonstrate how to connect to any Oracle Autonomous Database, including Autonomous Transaction Processing, Autonomous Data Warehouse, and Autonomous JSON Database, with a .NET console or ASP.NET web app. -Create a new .NET Framework project and add either managed or unmanaged ODP.NET assembly. Oracle recommends using managed ODP.NET for most .NET Framework apps. Managed ODP.NET ([Oracle.ManagedDataAccess](https://www.nuget.org/packages/Oracle.ManagedDataAccess)) can be downloaded from NuGet Gallery. Unmanaged ODP.NET can be added after an [ODAC installation](https://www.oracle.com/database/technologies/dotnet-odacdeploy-downloads.html). Paste the sample code into the project. You can then enter your ADB connection and configuration information into the sample code as described in the comments. - -This directory contains the -managed and unmanaged ODP.NET samples. The ODP.NET Core sample is located [here](https://github.com/oracle/dotnet-db-samples/tree/master/samples/dotnet-core/autonomous-db). +You can find an [Oracle Entity Framework Core for Autonomous Database code sample here](https://github.com/oracle/dotnet-db-samples/tree/master/samples/ef-core/autonomous-db). diff --git a/samples/autonomous-db/odp-core/console-app/no-wallet/autonomous-odp-core.cs b/samples/autonomous-db/odp-core/console-app/no-wallet/autonomous-odp-core.cs new file mode 100644 index 00000000..130a8b10 --- /dev/null +++ b/samples/autonomous-db/odp-core/console-app/no-wallet/autonomous-odp-core.cs @@ -0,0 +1,63 @@ +using System; +using Oracle.ManagedDataAccess.Client; + +namespace ODP.NET_Core_Autonomous +{ + class Program + { + static void Main(string[] args) + { + //Demo: ODP.NET Core application that connects to Oracle Autonomous DB without a wallet + + //Enter user id and password, such as ADMIN user + string conString = "User Id=;Password=;" + + + //Enter net service name or the full connect descriptor for data source value + "Data Source=;"; + + using (OracleConnection con = new OracleConnection(conString)) + { + using (OracleCommand cmd = con.CreateCommand()) + { + try + { + con.Open(); + + Console.WriteLine("Successfully connected to Oracle Autonomous Database"); + + //Retrieve database version info + cmd.CommandText = "SELECT BANNER FROM V$VERSION"; + OracleDataReader reader = cmd.ExecuteReader(); + reader.Read(); + Console.WriteLine("Connected to " + reader.GetString(0)); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + Console.ReadLine(); + } + } + } + } +} + +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/autonomous-db/console/autonomous-odp-core.cs b/samples/autonomous-db/odp-core/console-app/wallet/autonomous-odp-core.cs similarity index 100% rename from samples/dotnet-core/autonomous-db/console/autonomous-odp-core.cs rename to samples/autonomous-db/odp-core/console-app/wallet/autonomous-odp-core.cs index 45ddbaa8..934915b9 100644 --- a/samples/dotnet-core/autonomous-db/console/autonomous-odp-core.cs +++ b/samples/autonomous-db/odp-core/console-app/wallet/autonomous-odp-core.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using Oracle.ManagedDataAccess.Client; @@ -72,3 +53,22 @@ static void Main(string[] args) } } } + +/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/autonomous-db/web/Program.cs b/samples/autonomous-db/odp-core/web-app/aspnetcore3/Program.cs similarity index 100% rename from samples/dotnet-core/autonomous-db/web/Program.cs rename to samples/autonomous-db/odp-core/web-app/aspnetcore3/Program.cs diff --git a/samples/dotnet-core/autonomous-db/web/Startup.cs b/samples/autonomous-db/odp-core/web-app/aspnetcore3/Startup.cs similarity index 100% rename from samples/dotnet-core/autonomous-db/web/Startup.cs rename to samples/autonomous-db/odp-core/web-app/aspnetcore3/Startup.cs diff --git a/samples/autonomous-db/odp-core/web-app/aspnetcore6/Program.cs b/samples/autonomous-db/odp-core/web-app/aspnetcore6/Program.cs new file mode 100644 index 00000000..875fdb55 --- /dev/null +++ b/samples/autonomous-db/odp-core/web-app/aspnetcore6/Program.cs @@ -0,0 +1,64 @@ +using Oracle.ManagedDataAccess.Client; + +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.MapGet("/", () => "Hello World!"); + +app.Run(async context => +{ + //Set the user id and password + string conString = "User Id=ADMIN;Password=;Connection Timeout=180;" + + + //Set Data Source value to an Oracle connect descriptor or an Oracle net service name + "Data Source=;"; + + //If using Oracle client configuration files, uncomment line below and set the relative + // subdirectory of the website root directory where the files are located. + //OracleConfiguration.TnsAdmin = $".{Path.DirectorySeparatorChar}"; + + using (OracleConnection con = new OracleConnection(conString)) + { + using (OracleCommand cmd = con.CreateCommand()) + { + try + { + con.Open(); + await context.Response.WriteAsync("Connected to Oracle Autonomous Database." + "\n"); + + //Retrieve database version info + cmd.CommandText = "SELECT BANNER FROM V$VERSION"; + OracleDataReader reader = cmd.ExecuteReader(); + reader.Read(); + await context.Response.WriteAsync("The version is " + reader.GetString(0)); + + reader.Dispose(); + } + catch (Exception ex) + { + await context.Response.WriteAsync(ex.Message); + } + } + } +}); + +app.Run(); + +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/azure-active-directory/README.md b/samples/azure-active-directory/README.md new file mode 100644 index 00000000..8fb68474 --- /dev/null +++ b/samples/azure-active-directory/README.md @@ -0,0 +1,16 @@ +# Microsoft Entra ID/Azure Active Directory ODP.NET Sample Code +These ODP.NET sample code files show how to connect to an Oracle database using a token obtained from Microsoft Entra ID, also known as Azure Active Directory (AD), or with Azure AD single sign-on. + +In the main directory, there is one sample for each ODP.NET provider type (core, managed, and unmanaged). The samples shows Oracle access token management and Azure AD authentication. They require the following to test with an Azure AD token: +* Data Source +* Azure AD app registration client identifier +* Azure AD tenant identifier +* Azure AD app registration secret value +* Azure AD database registration scope + +In the SSO sub-directory, this sample shows how to use ODP.NET Azure AD SSO with service principal authentication. It can use either ODP.NET Core or managed ODP.NET and requires the following to test with: +* Data Source +* Azure AD app registration client identifier +* Azure AD tenant identifier +* Azure AD app registration secret value +* Azure AD protected resource identifier diff --git a/samples/azure-active-directory/azure-ad-odp-core.cs b/samples/azure-active-directory/azure-ad-odp-core.cs new file mode 100644 index 00000000..50195770 --- /dev/null +++ b/samples/azure-active-directory/azure-ad-odp-core.cs @@ -0,0 +1,97 @@ +// This is a simple ODP.NET, Core Driver application that connects to an Oracle Autonomous Database +// using a token obtained from Azure Active Directory (Azure AD). + +// Azure.Identity can be obtained through NuGet Gallery. +// It will include the Azure.Core and Azure.Identity namespaces. +using System; +using System.Threading; +using Azure.Core; +using Azure.Identity; +using Oracle.ManagedDataAccess.Client; + +namespace ConnectToOracleUsingAccessToken +{ + class Program + { + static void Main() + { + try + { + // Retrieve an access token from Azure AD. + string token = GetAccessToken(); + + // Create an instance of an OracleAccessToken. The access token needs to + // be passed to the OracleAccessToken constructor as array of characters. + var oracleAccessToken = new OracleAccessToken(token.ToCharArray()); + + // Create an instance of an OracleConnection object. + // The developer must provide the appropriate data source setting. + var connection = new OracleConnection("User Id=/;Data Source="); + + // tnsnames.ora, sqlnet.ora, and cwallet.sso must reside in the same + // directory as the application executable. These files can be downloaded + // from Oracle Cloud for the Oracle Autonomous DB instance. + connection.TnsAdmin = @".\"; + + // Assign the OracleAccessToken to the AccessToken property on the + // OracleConnection object. + connection.AccessToken = oracleAccessToken; + + // Open the connection. + connection.Open(); + + // If Open() fails, it will throw an exception. + Console.WriteLine("Open success."); + + // Dispose the OracleConnection object. + connection.Dispose(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + // Retrieves an Azure AD access token through the + // Service Principal Auth flow using a client secret. + static string GetAccessToken() + { + // The developer must configure the Azure AD parameters below. + string clientId = ""; + string tenantId = ""; + string clientSecret = ""; + string scope = ""; + + // Create a TokenRequestContext object. + var tokenRequestContext = new TokenRequestContext(new[] { scope }); + + // Create a ClientSecretCredential object. + var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret); + + // Get the access token from Azure AD. + AccessToken accessToken = credentials.GetToken(tokenRequestContext, default(CancellationToken)); + + // Return the access token. + return accessToken.Token; + } + } +} + +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/azure-active-directory/azure-ad-odp-managed.cs b/samples/azure-active-directory/azure-ad-odp-managed.cs new file mode 100644 index 00000000..b54b2cc5 --- /dev/null +++ b/samples/azure-active-directory/azure-ad-odp-managed.cs @@ -0,0 +1,97 @@ +// This is a simple ODP.NET, Managed Driver application that connects to an Oracle Autonomous Database +// using a token obtained from Azure Active Directory (Azure AD). + +// Azure.Identity can be obtained through NuGet Gallery. +// It will include the Azure.Core and Azure.Identity namespaces. +using System; +using System.Threading; +using Azure.Core; +using Azure.Identity; +using Oracle.ManagedDataAccess.Client; + +namespace ConnectToOracleUsingAccessToken +{ + class Program + { + static void Main() + { + try + { + // Retrieve an access token from Azure AD. + string token = GetAccessToken(); + + // Create an instance of an OracleAccessToken. The access token needs to + // be passed to the OracleAccessToken constructor as array of characters. + var oracleAccessToken = new OracleAccessToken(token.ToCharArray()); + + // Create an instance of an OracleConnection object. + // The developer must provide the appropriate data source setting. + var connection = new OracleConnection("User Id=/;Data Source="); + + // tnsnames.ora, sqlnet.ora, and cwallet.sso must reside in the same + // directory as the application executable. These files can be downloaded + // from Oracle Cloud for the Oracle Autonomous DB instance. + connection.TnsAdmin = @".\"; + + // Assign the OracleAccessToken to the AccessToken property on the + // OracleConnection object. + connection.AccessToken = oracleAccessToken; + + // Open the connection. + connection.Open(); + + // If Open() fails, it will throw an exception. + Console.WriteLine("Open success."); + + // Dispose the OracleConnection object. + connection.Dispose(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + // Retrieves an Azure AD access token through the + // Service Principal Auth flow using a client secret. + static string GetAccessToken() + { + // The developer must configure the Azure AD parameters below. + string clientId = ""; + string tenantId = ""; + string clientSecret = ""; + string scope = ""; + + // Create a TokenRequestContext object. + var tokenRequestContext = new TokenRequestContext(new[] { scope }); + + // Create a ClientSecretCredential object. + var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret); + + // Get the access token from Azure AD. + AccessToken accessToken = credentials.GetToken(tokenRequestContext, default(CancellationToken)); + + // Return the access token. + return accessToken.Token; + } + } +} + +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/azure-active-directory/azure-ad-odp-unmanaged.cs b/samples/azure-active-directory/azure-ad-odp-unmanaged.cs new file mode 100644 index 00000000..ba95b494 --- /dev/null +++ b/samples/azure-active-directory/azure-ad-odp-unmanaged.cs @@ -0,0 +1,96 @@ +// This is a simple ODP.NET, Unmanaged Driver application that connects to an Oracle Autonomous Database +// using a token obtained from Azure Active Directory (Azure AD). + +// Azure.Identity can be obtained through NuGet Gallery. +// It will include the Azure.Core and Azure.Identity namespaces. +using System; +using System.Threading; +using Azure.Core; +using Azure.Identity; +using Oracle.DataAccess.Client; + +namespace ConnectToOracleUsingAccessToken +{ + class Program + { + static void Main() + { + try + { + // Retrieve an access token from Azure AD. + string token = GetAccessToken(); + + // Create an instance of an OracleAccessToken. The access token needs to + // be passed to the OracleAccessToken constructor as array of characters. + var oracleAccessToken = new OracleAccessToken(token.ToCharArray()); + + // Create an instance of an OracleConnection object. + // The developer must provide the appropriate data source setting. + var connection = new OracleConnection("User Id=/;Data Source="); + + // tnsnames.ora, sqlnet.ora, and cwallet.sso must reside in the same + // directory as the application executable. These files can be downloaded + // from Oracle Cloud for the Oracle Autonomous DB instance. + + // Assign the OracleAccessToken to the AccessToken property on the + // OracleConnection object. + connection.AccessToken = oracleAccessToken; + + // Open the connection. + connection.Open(); + + // If Open() fails, it will throw an exception. + Console.WriteLine("Open success."); + + // Dispose the OracleConnection object. + connection.Dispose(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + // Retrieves an Azure AD access token through the + // Service Principal Auth flow using a client secret. + static string GetAccessToken() + { + // The developer must configure the Azure AD parameters below. + string clientId = ""; + string tenantId = ""; + string clientSecret = ""; + string scope = ""; + + // Create a TokenRequestContext object. + var tokenRequestContext = new TokenRequestContext(new[] { scope }); + + // Create a ClientSecretCredential object. + var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret); + + // Get the access token from Azure AD. + AccessToken accessToken = credentials.GetToken(tokenRequestContext, default(CancellationToken)); + + // Return the access token. + return accessToken.Token; + } + } +} + +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/azure-active-directory/sso/azure-ad-sso-service-principal.cs b/samples/azure-active-directory/sso/azure-ad-sso-service-principal.cs new file mode 100644 index 00000000..cc1b1ae6 --- /dev/null +++ b/samples/azure-active-directory/sso/azure-ad-sso-service-principal.cs @@ -0,0 +1,71 @@ +//This application demonstrates connecting .NET to Oracle database using Microsoft Entra ID/Azure Active +// Directory single sign-on (SSO). It uses service principal authentication with either managed ODP.NET or +// ODP.NET Core 23c or higher. + +// ODP.NET Azure AD SSO requires Oracle.ManagedDataAccess.Azure package from NuGet Gallery +using Oracle.ManagedDataAccess.Azure; +using Oracle.ManagedDataAccess.Client; +using System.Security; + +//Set your Azure Active Directory parameters below and ODP.NET data source value +string clientId = ""; +string tenantId = ""; +string clientSecret = ""; +string dbAppIdUri = ""; +var conn = new OracleConnection("User Id=/;Data Source=;Connection Timeout=900;"); + +var secureSecret = new SecureString(); +foreach (char c in clientSecret) +{ + secureSecret.AppendChar(c); +} +secureSecret.MakeReadOnly(); + +//Create Azure authentication token object and set its values. +var tokenConfig = new AzureTokenAuthentication +{ + ClientId = clientId, + TenantId = tenantId, + ClientSecret = secureSecret, + DatabaseApplicationIdUri = dbAppIdUri, +}; + +//Set token authentication mode to Azure Service Principal and use Azure token authentication +conn.TokenAuthentication = OracleTokenAuth.AzureServicePrincipal; +conn.UseAzureTokenAuthentication(tokenConfig); + +try +{ + conn.Open(); + Console.WriteLine("Connection opened successfully!"); + using (OracleCommand cmd = conn.CreateCommand()) + { + //Retrieve authenticated identity value from database + cmd.CommandText = "SELECT SYS_CONTEXT('USERENV', 'AUTHENTICATED_IDENTITY') FROM DUAL"; + Console.WriteLine($"Authenticated identity: {cmd.ExecuteScalar().ToString()}"); + } +} +catch (Exception ex) +{ + Console.WriteLine("Error: " + ex.Message); +} +conn.Dispose(); + +/* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/dotnet-db-samples/blob/master/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/bulk-copy/oracle-bulk-copy.cs b/samples/bulk-copy/oracle-bulk-copy.cs new file mode 100644 index 00000000..11b590f6 --- /dev/null +++ b/samples/bulk-copy/oracle-bulk-copy.cs @@ -0,0 +1,90 @@ +using Oracle.ManagedDataAccess.Client; +using System; + +class Program +{ + static void Main() + { + string connectionString = GetConnectionString(); + // Open a connection to the DB. + using (OracleConnection sourceConnection = new OracleConnection(connectionString)) + { + sourceConnection.Open(); + + // Perform an initial count on the source/destination table. + OracleCommand commandRowCount = new OracleCommand("SELECT COUNT(*) FROM BLOGS", sourceConnection); + long countStart = System.Convert.ToInt32(commandRowCount.ExecuteScalar()); + Console.WriteLine("Starting row count = {0}", countStart); + + // Get data from the source table as a OracleDataReader. + OracleCommand commandSourceData = new OracleCommand("SELECT ID, URL FROM BLOGS", sourceConnection); + OracleDataReader reader = commandSourceData.ExecuteReader(); + + // Open the destination connection. In the real world you would + // not use OracleBulkCopy to move data from one table to the other + // in the same database. This is for demonstration purposes only. + using (OracleConnection destinationConnection = new OracleConnection(connectionString)) + { + destinationConnection.Open(); + + // Set up the bulk copy object. + // Note that the column positions in the source data reader match the column positions in + // the destination table so there is no need to map columns. + using (OracleBulkCopy bulkCopy = new OracleBulkCopy(destinationConnection)) + { + bulkCopy.DestinationTableName = "BLOGS"; + + try + { + // Write from the source to the destination. + bulkCopy.WriteToServer(reader); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + // Close the OracleDataReader. The OracleBulkCopy object is automatically + // closed at the end of the using block. + reader.Close(); + } + } + + // Perform a final count on the destination table to see how many rows were added. + long countEnd = System.Convert.ToInt32( + commandRowCount.ExecuteScalar()); + Console.WriteLine("Ending row count = {0}", countEnd); + Console.WriteLine("{0} rows were added.", countEnd - countStart); + Console.WriteLine("Press Enter to finish."); + Console.ReadLine(); + } + } + } + + private static string GetConnectionString() + // Enter credentials below. + { + return "Data Source=; " + + "User Id=;" + + "Password=;"; + } +} + +/* Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) Microsoft */ + +/****************************************************************************** + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/bulk-copy/setup.sql b/samples/bulk-copy/setup.sql new file mode 100644 index 00000000..bea0ea63 --- /dev/null +++ b/samples/bulk-copy/setup.sql @@ -0,0 +1,3 @@ + /* This table is used by the ODP.NET Buulk Copy sample code. */ + /* Run this script to create the table. Populate it with a few rows. Then, run the ODP.NET sample. */ + CREATE TABLE "BLOGS" ("ID" NUMBER, "URL" VARCHAR2(50) NOT NULL ENABLE); diff --git a/samples/client-factory/ClientFactory.cs b/samples/client-factory/ClientFactory.cs index 733d2ca8..b43fca4d 100644 --- a/samples/client-factory/ClientFactory.cs +++ b/samples/client-factory/ClientFactory.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using System.Data; using System.Data.Common; @@ -54,3 +35,21 @@ static void Main() } } +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/client-factory/ClientFactory.csproj b/samples/client-factory/ClientFactory.csproj deleted file mode 100644 index 76721376..00000000 --- a/samples/client-factory/ClientFactory.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {87181B71-E623-4ED2-9403-B0450611DF1C} - Exe - Properties - ClientFactory - ClientFactory - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/command-builder/CommandBuilder1.csproj b/samples/command-builder/CommandBuilder1.csproj deleted file mode 100644 index 0a2abb94..00000000 --- a/samples/command-builder/CommandBuilder1.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {935DC831-8FF8-4C25-9398-37453B21A4E1} - Exe - Properties - CommandBuilder1 - CommandBuilder1 - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/command-builder/CommandBuilder2.csproj b/samples/command-builder/CommandBuilder2.csproj deleted file mode 100644 index e4337129..00000000 --- a/samples/command-builder/CommandBuilder2.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {73DAB672-407C-4125-8A90-307092EA6D88} - Exe - Properties - CommandBuilder2 - CommandBuilder2 - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/command-builder/CommandBuilder3.csproj b/samples/command-builder/CommandBuilder3.csproj deleted file mode 100644 index 7e501d39..00000000 --- a/samples/command-builder/CommandBuilder3.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {67FC1AC5-0578-442D-AF4E-A00061941726} - Exe - Properties - CommandBuilder3 - CommandBuilder3 - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/dotnet-core/configuration-api/DataSourceCollection-class.cs b/samples/configuration-api/DataSourceCollection-class.cs similarity index 99% rename from samples/dotnet-core/configuration-api/DataSourceCollection-class.cs rename to samples/configuration-api/DataSourceCollection-class.cs index e2d12e0a..c7ea51b3 100644 --- a/samples/dotnet-core/configuration-api/DataSourceCollection-class.cs +++ b/samples/configuration-api/DataSourceCollection-class.cs @@ -1,23 +1,3 @@ - -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using Oracle.ManagedDataAccess.Client; @@ -79,3 +59,22 @@ static void Main(string[] args) } } } + +/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/configuration-api/OnsServerCollection-class.cs b/samples/configuration-api/OnsServerCollection-class.cs similarity index 99% rename from samples/dotnet-core/configuration-api/OnsServerCollection-class.cs rename to samples/configuration-api/OnsServerCollection-class.cs index 8d5e3e8e..47cdeaa8 100644 --- a/samples/dotnet-core/configuration-api/OnsServerCollection-class.cs +++ b/samples/configuration-api/OnsServerCollection-class.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using Oracle.ManagedDataAccess.Client; @@ -78,3 +59,22 @@ static void Main(string[] args) } } } + +/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/configuration-api/README.md b/samples/configuration-api/README.md similarity index 100% rename from samples/dotnet-core/configuration-api/README.md rename to samples/configuration-api/README.md diff --git a/samples/dotnet-core/configuration-api/configuration-class.cs b/samples/configuration-api/configuration-class.cs similarity index 100% rename from samples/dotnet-core/configuration-api/configuration-class.cs rename to samples/configuration-api/configuration-class.cs index 431d975b..d00c0fe2 100644 --- a/samples/dotnet-core/configuration-api/configuration-class.cs +++ b/samples/configuration-api/configuration-class.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using Oracle.ManagedDataAccess.Client; @@ -88,3 +69,22 @@ static void Main(string[] args) } } } + +/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/connection-string-builder/ConnectionStringBuilder.cs b/samples/connection-string-builder/ConnectionStringBuilder.cs index 46ae7545..064ec50e 100644 --- a/samples/connection-string-builder/ConnectionStringBuilder.cs +++ b/samples/connection-string-builder/ConnectionStringBuilder.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using System.Data; using System.Data.Common; @@ -98,3 +79,21 @@ static void Main(string[] args) } } +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/connection-string-builder/ConnectionStringBuilder.csproj b/samples/connection-string-builder/ConnectionStringBuilder.csproj deleted file mode 100644 index f57927fa..00000000 --- a/samples/connection-string-builder/ConnectionStringBuilder.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {DADBFA91-A80E-48D7-8928-AD54880CD899} - Exe - Properties - ConnectionStringBuilder - ConnectionStringBuilder - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/connection/Connection1.csproj b/samples/connection/Connection1.csproj deleted file mode 100644 index 9f6047d6..00000000 --- a/samples/connection/Connection1.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {778FC99D-D045-4FD8-B968-11DA5D51E907} - Exe - Properties - Connection1 - Connection1 - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/connection/Connection2.csproj b/samples/connection/Connection2.csproj deleted file mode 100644 index e420373d..00000000 --- a/samples/connection/Connection2.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {62067470-7E93-40CD-BBDF-A5A78D359028} - Exe - Properties - Connection2 - Connection2 - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/connection/Connection3.csproj b/samples/connection/Connection3.csproj deleted file mode 100644 index 04d0d26d..00000000 --- a/samples/connection/Connection3.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {2DE7E3F7-7266-402F-8991-16364B405185} - Exe - Properties - Connection3 - Connection3 - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/data-reader/DataReader.csproj b/samples/data-reader/DataReader.csproj deleted file mode 100644 index ea9d43c0..00000000 --- a/samples/data-reader/DataReader.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {818E8A9A-B84E-4BE1-B65F-276CE97843C5} - Exe - Properties - DataReader - DataReader - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - diff --git a/samples/dotnet-core/DataReader/DataReader.cs b/samples/data-reader/core/DataReader.cs similarity index 100% rename from samples/dotnet-core/DataReader/DataReader.cs rename to samples/data-reader/core/DataReader.cs index 724af9ae..ee39d44e 100644 --- a/samples/dotnet-core/DataReader/DataReader.cs +++ b/samples/data-reader/core/DataReader.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using Oracle.ManagedDataAccess.Client; @@ -79,3 +60,22 @@ static void Main(string[] args) } } } + +/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/data-reader/DataReader.cs b/samples/data-reader/managed/DataReader.cs similarity index 100% rename from samples/data-reader/DataReader.cs rename to samples/data-reader/managed/DataReader.cs diff --git a/samples/data-source-enumerator/DataSourceEnumerator.cs b/samples/data-source-enumerator/DataSourceEnumerator.cs index a4f9b57c..dec7516b 100644 --- a/samples/data-source-enumerator/DataSourceEnumerator.cs +++ b/samples/data-source-enumerator/DataSourceEnumerator.cs @@ -1,3 +1,33 @@ +using System; +using System.Data; +using System.Data.Common; +using Oracle.ManagedDataAccess.Client; + +class DataSourceEnumSample +{ + static void Main() + { + string ProviderName = "Oracle.ManagedDataAccess.Client"; + + DbProviderFactory factory = DbProviderFactories.GetFactory(ProviderName); + + if (factory.CanCreateDataSourceEnumerator) + { + DbDataSourceEnumerator dsenum = factory.CreateDataSourceEnumerator(); + DataTable dt = dsenum.GetDataSources(); + + // Print the first column/row entry in the DataTable + Console.WriteLine(dt.Columns[0] + " : " + dt.Rows[0][0]); + Console.WriteLine(dt.Columns[1] + " : " + dt.Rows[0][1]); + Console.WriteLine(dt.Columns[2] + " : " + dt.Rows[0][2]); + Console.WriteLine(dt.Columns[3] + " : " + dt.Rows[0][3]); + Console.WriteLine(dt.Columns[4] + " : " + dt.Rows[0][4]); + } + else + Console.Write("Data source enumeration is not supported by provider"); + } +} + /* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** @@ -15,35 +45,4 @@ * See the License for the specific language governing permissions and * limitations under the License. * - *****************************************************************************/ - -using System; -using System.Data; -using System.Data.Common; -using Oracle.ManagedDataAccess.Client; - -class DataSourceEnumSample -{ - static void Main() - { - string ProviderName = "Oracle.ManagedDataAccess.Client"; - - DbProviderFactory factory = DbProviderFactories.GetFactory(ProviderName); - - if (factory.CanCreateDataSourceEnumerator) - { - DbDataSourceEnumerator dsenum = factory.CreateDataSourceEnumerator(); - DataTable dt = dsenum.GetDataSources(); - - // Print the first column/row entry in the DataTable - Console.WriteLine(dt.Columns[0] + " : " + dt.Rows[0][0]); - Console.WriteLine(dt.Columns[1] + " : " + dt.Rows[0][1]); - Console.WriteLine(dt.Columns[2] + " : " + dt.Rows[0][2]); - Console.WriteLine(dt.Columns[3] + " : " + dt.Rows[0][3]); - Console.WriteLine(dt.Columns[4] + " : " + dt.Rows[0][4]); - } - else - Console.Write("Data source enumeration is not supported by provider"); - } -} - + *****************************************************************************/ diff --git a/samples/data-source-enumerator/DataSourceEnumerator.csproj b/samples/data-source-enumerator/DataSourceEnumerator.csproj deleted file mode 100644 index 6e0fee44..00000000 --- a/samples/data-source-enumerator/DataSourceEnumerator.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {8BB7A6DC-F680-434F-9594-65726212895D} - Exe - Properties - DataSourceEnumerator - DataSourceEnumerator - v4.0 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/dataset/DML/src/DMLOperOnDS.csproj b/samples/dataset/DML/src/DMLOperOnDS.csproj deleted file mode 100644 index 4259c040..00000000 --- a/samples/dataset/DML/src/DMLOperOnDS.csproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {D93F7A67-9711-11D6-8205-0002A577685A} - Debug - AnyCPU - - - - - DMLOperOnDS - v4.0 - - - JScript - Grid - IE50 - false - Exe - DMLOperOnDS - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.Drawing - - - System.Windows.Forms - - - System.XML - - - - - Code - - - Form - - - ManipulateProducts.cs - - - - - - - - - - \ No newline at end of file diff --git a/samples/dataset/fill/src/DSPopulate.csproj b/samples/dataset/fill/src/DSPopulate.csproj deleted file mode 100644 index cd0c5af1..00000000 --- a/samples/dataset/fill/src/DSPopulate.csproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {8C0E9C27-8F4C-11D6-8202-0002A577685A} - Debug - AnyCPU - - - - - DSPopulate - v4.0 - - - JScript - Grid - IE50 - false - Exe - DSPopulate - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.Drawing - - - System.Windows.Forms - - - System.XML - - - - - Code - - - Form - - - ViewProducts.cs - - - - - - - - - - \ No newline at end of file diff --git a/samples/dataset/lob/src/DSDRwithLOB.csproj b/samples/dataset/lob/src/DSDRwithLOB.csproj deleted file mode 100644 index 84926579..00000000 --- a/samples/dataset/lob/src/DSDRwithLOB.csproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {CE7822B9-9324-11D6-8202-0002A577685A} - Debug - AnyCPU - - - - - DSwithLOB - v4.0 - - - JScript - Grid - IE50 - false - Exe - DSDRwithLOB - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.Drawing - - - System.Windows.Forms - - - System.XML - - - - - Code - - - Form - - - ManipulateAds.cs - - - - - - - - - - \ No newline at end of file diff --git a/samples/dataset/ref-cursor/src/DSwithRefCur.csproj b/samples/dataset/ref-cursor/src/DSwithRefCur.csproj deleted file mode 100644 index fb7e8e1d..00000000 --- a/samples/dataset/ref-cursor/src/DSwithRefCur.csproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {7EA8A9AD-93D2-11D6-8203-0002A577685A} - Debug - AnyCPU - - - - - DSwithRefCur - v4.0 - - - JScript - Grid - IE50 - false - Exe - DSwithRefCur - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.Drawing - - - System.Windows.Forms - - - System.XML - - - - - Code - - - Form - - - ViewProducts.cs - - - - - - - - - - \ No newline at end of file diff --git a/samples/dataset/vb/src/DSPopulateVB.vbproj b/samples/dataset/vb/src/DSPopulateVB.vbproj deleted file mode 100644 index 6a9a25ba..00000000 --- a/samples/dataset/vb/src/DSPopulateVB.vbproj +++ /dev/null @@ -1,121 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {765DA110-9421-11D6-8203-0002A577685A} - Debug - AnyCPU - - - - - DSPopulate - v4.0 - - - None - JScript - Grid - IE50 - false - WinExe - Binary - On - Off - DSPopulate - DSPopulate.viewProductsFrm - - - WindowsFormsWithCustomSubMain - - - - - bin\ - DSPopulate.xml - 285212672 - - - - - true - true - true - false - false - false - false - 1 - 42016,42017,42018,42019,42032 - full - - - bin\ - DSPopulate.xml - 285212672 - - - - - false - true - false - true - false - false - false - 1 - 42016,42017,42018,42019,42032 - none - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.Drawing - - - System.Windows.Forms - - - System.XML - - - - - - - - - - - - - - Code - - - Form - - - ViewProductsFrm.vb - - - - - - - - - - \ No newline at end of file diff --git a/samples/dotnet-core/DataReader/DataReader.csproj b/samples/dotnet-core/DataReader/DataReader.csproj deleted file mode 100644 index 8e047a01..00000000 --- a/samples/dotnet-core/DataReader/DataReader.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - Exe - netcoreapp2.0 - - - diff --git a/samples/dotnet-core/autonomous-db/README.md b/samples/dotnet-core/autonomous-db/README.md deleted file mode 100644 index 8ef7a507..00000000 --- a/samples/dotnet-core/autonomous-db/README.md +++ /dev/null @@ -1,10 +0,0 @@ -The ODP.NET Core Autonomous Database (ADB) code sample in the "console" subdirectory is intended to be used with the [Developing .NET Core Applications for Oracle Autonomous Database tutorial](https://www.oracle.com/database/technologies/appdev/dotnet/adbdotnetcore.html). - -This sample demonstrates how to connect to Oracle Autonomous Database, including Oracle Autonomous Transaction Processing and Autonomous Data Warehouse. - -Create a new .NET Core console project, add ODP.NET Core assembly ([Oracle.ManagedDataAccess.Core](https://www.nuget.org/packages/Oracle.ManagedDataAccess.Core/)) from NuGet Gallery, and paste the sample code. You can then enter your ADB connection and configuration information into the pasted sample code as described in the comments. - -This repository has ADB code samples for ODP.NET Core, managed ODP.NET, and unmanaged ODP.NET. This directory contains the -ODP.NET Core sample. The other ODP.NET Autonomous DB samples are located [here](https://github.com/oracle/dotnet-db-samples/tree/master/samples/autonomous-db). - -The "web" subdirectory contains an ADB sample using ASP.NET Core and ODP.NET Core. diff --git a/samples/dotnet-core/ef-core/autonomous-db/README.md b/samples/ef-core/autonomous-db/README.md similarity index 64% rename from samples/dotnet-core/ef-core/autonomous-db/README.md rename to samples/ef-core/autonomous-db/README.md index dac5bbef..6b5f6bc9 100644 --- a/samples/dotnet-core/ef-core/autonomous-db/README.md +++ b/samples/ef-core/autonomous-db/README.md @@ -1,4 +1,4 @@ -This sample code demonstrates using ODP.NET Entity Framework Core with an Oracle Autonomous Database (ADB). It is compatible with EF Core 2.x and 3.x. It builds off [this introductory sample](https://github.com/oracle/dotnet-db-samples/blob/master/samples/dotnet-core/ef-core/get-started/) for Oracle EF Core beginners. In this sample, ADB connection setup occurs in the OnConfiguring method. +This sample code demonstrates using ODP.NET Entity Framework Core with an Oracle Autonomous Database (ADB). It builds off [this introductory sample](https://github.com/oracle/dotnet-db-samples/blob/master/samples/ef-core/get-started/) for Oracle EF Core beginners. In this sample, ADB connection setup occurs in the OnConfiguring method. 1. Set the OracleConfiguration.TnsAdmin property value to the tnsnames.ora and sqlnet.ora files directory location. diff --git a/samples/dotnet-core/ef-core/autonomous-db/adb-odp-efcore.cs b/samples/ef-core/autonomous-db/adb-odp-efcore.cs similarity index 97% rename from samples/dotnet-core/ef-core/autonomous-db/adb-odp-efcore.cs rename to samples/ef-core/autonomous-db/adb-odp-efcore.cs index 75dc0d15..183efcd8 100644 --- a/samples/dotnet-core/ef-core/autonomous-db/adb-odp-efcore.cs +++ b/samples/ef-core/autonomous-db/adb-odp-efcore.cs @@ -1,26 +1,7 @@ -/* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System.Collections.Generic; using Microsoft.EntityFrameworkCore; -// ODP.NET namespace added to access OracleConfiguration class +// ODP.NET namespace added using Oracle.ManagedDataAccess.Client; namespace OracleEFCore_ADB @@ -35,7 +16,6 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - // Configure ODP.NET connection string optionsBuilder.UseOracle(@"User Id=;Password=;Data Source="); } @@ -80,3 +60,22 @@ static void Main(string[] args) } } } + +/* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/ef-core/dependency-injection/Controllers/BlogsController.cs b/samples/ef-core/dependency-injection/Controllers/BlogsController.cs similarity index 100% rename from samples/dotnet-core/ef-core/dependency-injection/Controllers/BlogsController.cs rename to samples/ef-core/dependency-injection/Controllers/BlogsController.cs diff --git a/samples/dotnet-core/ef-core/dependency-injection/Models/BloggingContext.cs b/samples/ef-core/dependency-injection/Models/BloggingContext.cs similarity index 100% rename from samples/dotnet-core/ef-core/dependency-injection/Models/BloggingContext.cs rename to samples/ef-core/dependency-injection/Models/BloggingContext.cs diff --git a/samples/dotnet-core/ef-core/dependency-injection/Program.cs b/samples/ef-core/dependency-injection/Program.cs similarity index 100% rename from samples/dotnet-core/ef-core/dependency-injection/Program.cs rename to samples/ef-core/dependency-injection/Program.cs diff --git a/samples/dotnet-core/ef-core/dependency-injection/README.md b/samples/ef-core/dependency-injection/README.md similarity index 100% rename from samples/dotnet-core/ef-core/dependency-injection/README.md rename to samples/ef-core/dependency-injection/README.md diff --git a/samples/dotnet-core/ef-core/dependency-injection/Startup.cs b/samples/ef-core/dependency-injection/Startup.cs similarity index 100% rename from samples/dotnet-core/ef-core/dependency-injection/Startup.cs rename to samples/ef-core/dependency-injection/Startup.cs diff --git a/samples/dotnet-core/ef-core/dependency-injection/Views/Blogs/Index.cshtml b/samples/ef-core/dependency-injection/Views/Blogs/Index.cshtml similarity index 100% rename from samples/dotnet-core/ef-core/dependency-injection/Views/Blogs/Index.cshtml rename to samples/ef-core/dependency-injection/Views/Blogs/Index.cshtml diff --git a/samples/dotnet-core/ef-core/dependency-injection/appsettings.json b/samples/ef-core/dependency-injection/appsettings.json similarity index 100% rename from samples/dotnet-core/ef-core/dependency-injection/appsettings.json rename to samples/ef-core/dependency-injection/appsettings.json diff --git a/samples/dotnet-core/ef-core/get-started/README.md b/samples/ef-core/get-started/README.md similarity index 67% rename from samples/dotnet-core/ef-core/get-started/README.md rename to samples/ef-core/get-started/README.md index 6378b63b..ffc6095e 100644 --- a/samples/dotnet-core/ef-core/get-started/README.md +++ b/samples/ef-core/get-started/README.md @@ -1,3 +1,11 @@ +# Getting Started with Oracle Entity Framework Core + +There are two sets of sample code showing how to perform several basic tasks with Oracle EF Core. +1. [Getting Started with Oracle EF Core 6 and higher](https://github.com/oracle/dotnet-db-samples/blob/master/samples/ef-core/get-started/create-model-save-query-scaffold-efc.cs) +2. [Getting Started with Oracle EF Core 5 and earlier releases](https://github.com/oracle/dotnet-db-samples/blob/master/samples/ef-core/get-started/create-model-save-query-scaffold.cs) + +The sample code and below instructions show how to create a data model, save it to an Oracle database, insert data, query the data, use migrations to modify the schema, and reverse engineer. + Oracle Entity Framework Core is currently available on [nuget.org](https://www.nuget.org/packages/Oracle.EntityFrameworkCore/). To use the sample code, create a new Oracle user. Log into the Oracle Database with DBA privileges and run the following commands: @@ -32,6 +40,6 @@ You will now see a new Rating column in the Blog table. To generate .NET code for a DbContext and entity types from a database, run the following command in the PMC: -* Scaffold-DbContext "User Id=blog;Password=blog;Data Source=\;" Oracle.EntityFrameworkCore -OutputDir Models +* Scaffold-DbContext "User Id=blog;Password=\;Data Source=\;" Oracle.EntityFrameworkCore -OutputDir Models A "Models" directory will be created in your Visual Studio project with EF Core generated code based on the Oracle schema. diff --git a/samples/ef-core/get-started/create-model-save-query-scaffold-efc.cs b/samples/ef-core/get-started/create-model-save-query-scaffold-efc.cs new file mode 100644 index 00000000..495d92c2 --- /dev/null +++ b/samples/ef-core/get-started/create-model-save-query-scaffold-efc.cs @@ -0,0 +1,81 @@ +using Microsoft.EntityFrameworkCore; + +namespace OracleEFCore +{ + class Program + { + //Demonstrates how to get started using Oracle Entity Framework Core 6 and higher + //Code connects to on-premises Oracle DB or walletless Oracle Autonomous DB + + public class BloggingContext : DbContext + { + public DbSet? Blogs { get; set; } + public DbSet? Posts { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseOracle(@"User Id=blog;Password=;Data Source="); + } + } + + public class Blog + { + public int BlogId { get; set; } + public string? Url { get; set; } + //public int? Rating { get; set; } + public List? Posts { get; set; } + } + + public class Post + { + public int PostId { get; set; } + public string? Title { get; set; } + public string? Content { get; set; } + + public int BlogId { get; set; } + public Blog? Blog { get; set; } + } + + static void Main(string[] args) + { + + using (var db = new BloggingContext()) + { + var blog = new Blog { Url = "https://blogs.oracle.com" }; + //var blog = new Blog { Url = "https://blogs.oracle.com", Rating = 10 }; + db.Blogs!.Add(blog); + db.SaveChanges(); + } + + using (var db = new BloggingContext()) + { + var blogs = db.Blogs; + foreach (var item in blogs!) + { + Console.WriteLine(item.Url); + //Console.WriteLine(item.Url + " has rating " + item.Rating ); + } + } + Console.ReadLine(); + } + } +} + +/* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/dotnet-db-samples/blob/master/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/ef-core/get-started/create-model-save-query-scaffold.cs b/samples/ef-core/get-started/create-model-save-query-scaffold.cs similarity index 96% rename from samples/dotnet-core/ef-core/get-started/create-model-save-query-scaffold.cs rename to samples/ef-core/get-started/create-model-save-query-scaffold.cs index ce0718e8..a3ba76eb 100644 --- a/samples/dotnet-core/ef-core/get-started/create-model-save-query-scaffold.cs +++ b/samples/ef-core/get-started/create-model-save-query-scaffold.cs @@ -1,21 +1,3 @@ -/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ -/* Copyright (c) .NET Foundation and Contributors */ - -/****************************************************************************** - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System.Collections.Generic; using Microsoft.EntityFrameworkCore; @@ -69,3 +51,21 @@ static void Main(string[] args) } } } + +/* Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) .NET Foundation and Contributors */ + +/****************************************************************************** + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/ef-core/json/json-columns.cs b/samples/ef-core/json/json-columns.cs new file mode 100644 index 00000000..7f0434f8 --- /dev/null +++ b/samples/ef-core/json/json-columns.cs @@ -0,0 +1,171 @@ +//This sample shows how to use EF Core JSON columns with ODP.NET and Oracle Database. +//It creates an owned entity, inserts, queries, updates, and deletes JSON column data. +//It requires Oracle EF Core 8 or higher. Oracle Database 21c and higher supports JSON columns. +//Earlier database versions map aggregate types to NCLOB columns instead of JSON columns. + +//Specify the user, password, and data source in the connection string below. + +using Microsoft.EntityFrameworkCore; + +namespace ODPJsonColumns +{ + class Program + { + public class ContactDetails + { + public Address Address { get; set; } = null!; + public string? Phone { get; set; } + } + + public class Address + { + public Address(string street, string city, string postcode, string country) + { + Street = street; + City = city; + Postcode = postcode; + Country = country; + } + + public string Street { get; set; } + public string City { get; set; } + public string Postcode { get; set; } + public string Country { get; set; } + } + + public class Author + { + public int Id { get; set; } + public string? Name { get; set; } + public ContactDetails? Contact { get; set; } + } + + public class AuthorContext : DbContext + { + public DbSet Authors { get; set; } + + //To use Oracle database JSON columns, connect to Oracle Database 21c or higher version and + // specify OracleSQLCompatibility to DatabaseVersion21 or higher. + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseOracle("User Id=; Password=; Data Source=" + , b => b.UseOracleSQLCompatibility(OracleSQLCompatibility.DatabaseVersion21)); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + // Configuring the Contact column as a JSON column + modelBuilder.Entity().OwnsOne( + author => author.Contact, ownedNavigationBuilder => + { + ownedNavigationBuilder.ToJson(); + ownedNavigationBuilder.OwnsOne(contactDetails => contactDetails.Address); + }); + } + } + + public static void Main() + { + using (var context = new AuthorContext()) + { + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); + + var author1 = new Author() + { + Name = "John Smith", + Contact = new ContactDetails() + { + Phone = "555 123 4567", + Address = new Address("1 Any Street", "Austin", "78741", "US") + } + }; + + var author2 = new Author() + { + Name = "Kim Jones", + Contact = new ContactDetails() + { + Phone = "555 234 5678", + Address = new Address("2 Any Street", "Redwood Shores", "94065", "US") + } + }; + + /* + * Contact inserted into the JSON column as the following example: + * + * { + * "Phone": "555 123 4567", + * "Address": { + * "City": "Austin", + * "Country": "US", + * "Postcode": "78741", + * "Street": "1 Any Street" + * } + * } + */ + + // Insert data + Console.WriteLine("Inserting authors into table\n"); + context.Authors.Add(author1); + context.Authors.Add(author2); + context.SaveChanges(); + + // Query to verify insert + Console.WriteLine("Authors in table: "); + var result = context.Authors.ToList(); + foreach (var author in result) + { + Console.WriteLine($"{author.Name}"); + } + Console.WriteLine(); + + // Query using owned entity details from JSON column + var result1 = context.Authors.Where(author => author.Contact.Address.City == "Austin").First(); + Console.WriteLine($"Author residing in Austin: {result1.Name}\n"); + + // Update second author's phone number details + Console.WriteLine("Updating second author's phone number"); + author2.Contact.Phone = "123 456 7890"; + context.SaveChanges(); + + // Query to verify update + var result2 = context.Authors.Where(author => author.Name == "Kim Jones").First(); + Console.WriteLine($"Retrieve author's new phone number {result2.Name}: {result2.Contact.Phone}\n"); + + // Delete second author + Console.WriteLine("Deleting author with street address '2 Any Street' from table"); + context.Remove(context.Authors.Single(author => author.Contact.Address.Street == "2 Any Street")); + context.SaveChanges(); + Console.WriteLine("Delete complete.\n"); + + // Query to verify delete + Console.WriteLine("Authors remaining in table: "); + var result3 = context.Authors.ToList(); + foreach(var author in result3) + { + Console.WriteLine($"{author.Name}"); + } + } + } + } +} + +/* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/dotnet-db-samples/blob/master/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/ef-core/keyless-entity-types-views/README.md b/samples/ef-core/keyless-entity-types-views/README.md similarity index 92% rename from samples/dotnet-core/ef-core/keyless-entity-types-views/README.md rename to samples/ef-core/keyless-entity-types-views/README.md index bc5fc987..2f9d05b6 100644 --- a/samples/dotnet-core/ef-core/keyless-entity-types-views/README.md +++ b/samples/ef-core/keyless-entity-types-views/README.md @@ -4,7 +4,7 @@ This sample uses Oracle EF Core 3.1 provider, which is available as a free downl To use the sample code, enter the User Id, Password, and Data Source values for the Oracle database connection string. -Ensure the EF Core user has the database privileges to create the necessary schema objects to run the sample code. If you have granted the privileges in the [Oracle EF Core Getting Started sample](https://github.com/oracle/dotnet-db-samples/tree/master/samples/dotnet-core/ef-core/get-started) already, then you only need to grant view creation privileges: +Ensure the EF Core user has the database privileges to create the necessary schema objects to run the sample code. If you have granted the privileges in the [Oracle EF Core Getting Started sample](https://github.com/oracle/dotnet-db-samples/tree/master/samples/ef-core/get-started) already, then you only need to grant view creation privileges: * GRANT CREATE VIEW TO "<Oracle User>" * GRANT CREATE MATERIALIZED VIEW TO "<Oracle User>" diff --git a/samples/dotnet-core/ef-core/keyless-entity-types-views/keyless-entity-types-views.cs b/samples/ef-core/keyless-entity-types-views/keyless-entity-types-views.cs similarity index 99% rename from samples/dotnet-core/ef-core/keyless-entity-types-views/keyless-entity-types-views.cs rename to samples/ef-core/keyless-entity-types-views/keyless-entity-types-views.cs index 2841284f..4754a7c7 100644 --- a/samples/dotnet-core/ef-core/keyless-entity-types-views/keyless-entity-types-views.cs +++ b/samples/ef-core/keyless-entity-types-views/keyless-entity-types-views.cs @@ -1,21 +1,3 @@ -/* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. */ -/* Copyright (c) .NET Foundation */ - -/****************************************************************************** - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using System.Collections.Generic; using System.Linq; @@ -191,3 +173,21 @@ public class MVBlogPostsCount } #endregion } + +/* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. */ +/* Copyright (c) .NET Foundation */ + +/****************************************************************************** + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/dotnet-core/ef-core/stored-procedure/README.md b/samples/ef-core/stored-procedure/README.md similarity index 100% rename from samples/dotnet-core/ef-core/stored-procedure/README.md rename to samples/ef-core/stored-procedure/README.md diff --git a/samples/dotnet-core/ef-core/stored-procedure/return-implicit-ref-cursor-stored-procedure.sql b/samples/ef-core/stored-procedure/return-implicit-ref-cursor-stored-procedure.sql similarity index 99% rename from samples/dotnet-core/ef-core/stored-procedure/return-implicit-ref-cursor-stored-procedure.sql rename to samples/ef-core/stored-procedure/return-implicit-ref-cursor-stored-procedure.sql index 2aaa7c9c..a693aafe 100644 --- a/samples/dotnet-core/ef-core/stored-procedure/return-implicit-ref-cursor-stored-procedure.sql +++ b/samples/ef-core/stored-procedure/return-implicit-ref-cursor-stored-procedure.sql @@ -1,3 +1,15 @@ +CREATE OR REPLACE +PROCEDURE "GETALLBLOGS_IMPLICIT" +AS + BLOGRESULTS SYS_REFCURSOR; + +BEGIN + + OPEN BLOGRESULTS FOR SELECT * FROM "Blogs"; + DBMS_SQL.RETURN_RESULT(BLOGRESULTS); + +END; + /* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** @@ -16,15 +28,3 @@ * limitations under the License. * *****************************************************************************/ - -CREATE OR REPLACE -PROCEDURE "GETALLBLOGS_IMPLICIT" -AS - BLOGRESULTS SYS_REFCURSOR; - -BEGIN - - OPEN BLOGRESULTS FOR SELECT * FROM "Blogs"; - DBMS_SQL.RETURN_RESULT(BLOGRESULTS); - -END; diff --git a/samples/dotnet-core/ef-core/stored-procedure/return-ref-cursor-stored-procedure.sql b/samples/ef-core/stored-procedure/return-ref-cursor-stored-procedure.sql similarity index 100% rename from samples/dotnet-core/ef-core/stored-procedure/return-ref-cursor-stored-procedure.sql rename to samples/ef-core/stored-procedure/return-ref-cursor-stored-procedure.sql index 2ebe0782..bd36ffaa 100644 --- a/samples/dotnet-core/ef-core/stored-procedure/return-ref-cursor-stored-procedure.sql +++ b/samples/ef-core/stored-procedure/return-ref-cursor-stored-procedure.sql @@ -1,3 +1,13 @@ +CREATE OR REPLACE +PROCEDURE "GETALLBLOGS" ( +"BLOGRESULTS" OUT SYS_REFCURSOR) IS + +BEGIN + + OPEN BLOGRESULTS FOR SELECT * FROM "Blogs"; + +END; + /* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ /****************************************************************************** @@ -16,13 +26,3 @@ * limitations under the License. * *****************************************************************************/ - -CREATE OR REPLACE -PROCEDURE "GETALLBLOGS" ( -"BLOGRESULTS" OUT SYS_REFCURSOR) IS - -BEGIN - - OPEN BLOGRESULTS FOR SELECT * FROM "Blogs"; - -END; diff --git a/samples/dotnet-core/ef-core/stored-procedure/return-ref-cursor.cs b/samples/ef-core/stored-procedure/return-ref-cursor.cs similarity index 100% rename from samples/dotnet-core/ef-core/stored-procedure/return-ref-cursor.cs rename to samples/ef-core/stored-procedure/return-ref-cursor.cs index e1abb9c3..ffa7ddbc 100644 --- a/samples/dotnet-core/ef-core/stored-procedure/return-ref-cursor.cs +++ b/samples/ef-core/stored-procedure/return-ref-cursor.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System.Collections.Generic; using System.Linq; using System.Data; @@ -102,3 +83,22 @@ static void Main(string[] args) } } } + +/* Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/ef-core/t4-templates/README.md b/samples/ef-core/t4-templates/README.md new file mode 100644 index 00000000..6acda932 --- /dev/null +++ b/samples/ef-core/t4-templates/README.md @@ -0,0 +1,8 @@ +# Customize Oracle EF Core Data Type Mappings with T4 Text Templates + +Oracle EF Core data type mapping between entity properties and database columns can be customized with T4 text templates. This repository includes sample T4 templates that can be used as is or customized with an alternative set of .NET data type mappings. The samples demonstrate the following mapping scenarios: + +* All Numeric Types - Customizes all database numeric column type mappings to .NET properties +* Single Numeric Type - Customizes one database column type mapping to a specific .NET property + +The [ODP.NET Scaffolding documentation](https://docs.oracle.com/en/database/oracle/oracle-database/23/odpnt/EFCoreREDataTypeMapping.html) provides more information and a step-by-step usage guide. diff --git a/samples/ef-core/t4-templates/all-numeric-types/EntityType.t4 b/samples/ef-core/t4-templates/all-numeric-types/EntityType.t4 new file mode 100644 index 00000000..ac84227c --- /dev/null +++ b/samples/ef-core/t4-templates/all-numeric-types/EntityType.t4 @@ -0,0 +1,209 @@ +<# // Sample Oracle T4 template to customize mapping all database numeric column types to .NET properties. The mapped .NET properties store a superset of values of their mapped database types. #> + +<#@ template hostSpecific="true" #> +<#@ assembly name="Microsoft.EntityFrameworkCore" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Relational" #> +<#@ assembly name="Microsoft.Extensions.DependencyInjection.Abstractions" #> +<#@ parameter name="EntityType" type="Microsoft.EntityFrameworkCore.Metadata.IEntityType" #> +<#@ parameter name="Options" type="Microsoft.EntityFrameworkCore.Scaffolding.ModelCodeGenerationOptions" #> +<#@ parameter name="NamespaceHint" type="System.String" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.ComponentModel.DataAnnotations" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="Microsoft.EntityFrameworkCore" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Design" #> +<#@ import namespace="Microsoft.Extensions.DependencyInjection" #> +<# + if (EntityType.IsSimpleManyToManyJoinEntityType()) + { + // Don't scaffold these + return ""; + } + + var services = (IServiceProvider)Host; + var annotationCodeGenerator = services.GetRequiredService(); + var code = services.GetRequiredService(); + + var usings = new List + { + "System", + "System.Collections.Generic" + }; + + if (Options.UseDataAnnotations) + { + usings.Add("System.ComponentModel.DataAnnotations"); + usings.Add("System.ComponentModel.DataAnnotations.Schema"); + usings.Add("Microsoft.EntityFrameworkCore"); + } + + if (!string.IsNullOrEmpty(NamespaceHint)) + { +#> +namespace <#= NamespaceHint #>; + +<# + } + + if (!string.IsNullOrEmpty(EntityType.GetComment())) + { +#> +/// +/// <#= code.XmlComment(EntityType.GetComment()) #> +/// +<# + } + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in EntityType.GetDataAnnotations(annotationCodeGenerator)) + { +#> +<#= code.Fragment(dataAnnotation) #> +<# + } + } +#> +public partial class <#= EntityType.Name #> +{ +<# + var firstProperty = true; + foreach (var property in EntityType.GetProperties().OrderBy(p => p.GetColumnOrder() ?? -1)) + { + if (!firstProperty) + { + WriteLine(""); + } + + if (!string.IsNullOrEmpty(property.GetComment())) + { +#> + /// + /// <#= code.XmlComment(property.GetComment(), indent: 1) #> + /// +<# + } + + if (Options.UseDataAnnotations) + { + var dataAnnotations = property.GetDataAnnotations(annotationCodeGenerator) + .Where(a => !(a.Type == typeof(RequiredAttribute) && Options.UseNullableReferenceTypes && !property.ClrType.IsValueType)); + foreach (var dataAnnotation in dataAnnotations) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } + + // Make changes here to customize type mapping for all properties of certain column types. + Type clrType; + string columnType = property.GetColumnType(); // Get the store type for which we want custom mapping. + + if (columnType == "NUMBER(1)") + { + clrType = Options.UseNullableReferenceTypes && property.IsNullable ? typeof(byte?) : typeof(byte); // Map NUMBER(1) to byte. + } + else if (columnType == "NUMBER(2)" || columnType == "NUMBER(3)" || columnType == "NUMBER(4)") + { + clrType = Options.UseNullableReferenceTypes && property.IsNullable ? typeof(Int16?) : typeof(Int16); // Map NUMBER(2) to NUMBER(4) to Int16. + } + else if (columnType == "NUMBER(5)") + { + clrType = Options.UseNullableReferenceTypes && property.IsNullable ? typeof(Int32?) : typeof(Int32); // Map NUMBER(5) to Int32. + } + else if (columnType == "NUMBER(6)" || columnType == "NUMBER(7)" || columnType == "NUMBER(8)" || + columnType == "NUMBER(9)" || columnType == "NUMBER(10)") + { + clrType = Options.UseNullableReferenceTypes && property.IsNullable ? typeof(Int64?) : typeof(Int64); // Map NUMBER(6) to NUMBER(10) to Int64. + } + else if (columnType == "NUMBER(11)" || columnType == "NUMBER(12)" || columnType == "NUMBER(13)" || + columnType == "NUMBER(14)" || columnType == "NUMBER(15)" || columnType == "NUMBER(16)" || + columnType == "NUMBER(17)" || columnType == "NUMBER(18)" || columnType == "NUMBER(19)") + { + clrType = Options.UseNullableReferenceTypes && property.IsNullable ? typeof(Decimal?) : typeof(Decimal); // Map NUMBER(11) to NUMBER(19) to Decimal. + } + // Add more column types as required. + else + { + clrType = property.ClrType; // Keep the default CLR Type. + } + + + usings.AddRange(code.GetRequiredUsings(clrType)); + + var needsNullable = Options.UseNullableReferenceTypes && property.IsNullable && !clrType.IsValueType; + var needsInitializer = Options.UseNullableReferenceTypes && !property.IsNullable && !clrType.IsValueType; +#> + public <#= code.Reference(clrType) #><#= needsNullable ? "?" : "" #> <#= property.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #> +<# + firstProperty = false; + } + + foreach (var navigation in EntityType.GetNavigations()) + { + WriteLine(""); + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in navigation.GetDataAnnotations(annotationCodeGenerator)) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } + + var targetType = navigation.TargetEntityType.Name; + if (navigation.IsCollection) + { +#> + public virtual ICollection<<#= targetType #>> <#= navigation.Name #> { get; set; } = new List<<#= targetType #>>(); +<# + } + else + { + var needsNullable = Options.UseNullableReferenceTypes && !(navigation.ForeignKey.IsRequired && navigation.IsOnDependent); + var needsInitializer = Options.UseNullableReferenceTypes && navigation.ForeignKey.IsRequired && navigation.IsOnDependent; +#> + public virtual <#= targetType #><#= needsNullable ? "?" : "" #> <#= navigation.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #> +<# + } + } + + foreach (var skipNavigation in EntityType.GetSkipNavigations()) + { + WriteLine(""); + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in skipNavigation.GetDataAnnotations(annotationCodeGenerator)) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } +#> + public virtual ICollection<<#= skipNavigation.TargetEntityType.Name #>> <#= skipNavigation.Name #> { get; set; } = new List<<#= skipNavigation.TargetEntityType.Name #>>(); +<# + } +#> +} +<# + var previousOutput = GenerationEnvironment; + GenerationEnvironment = new StringBuilder(); + + foreach (var ns in usings.Distinct().OrderBy(x => x, new NamespaceComparer())) + { +#> +using <#= ns #>; +<# + } + + WriteLine(""); + + GenerationEnvironment.Append(previousOutput); +#> diff --git a/samples/ef-core/t4-templates/single-numeric-type/EntityType.t4 b/samples/ef-core/t4-templates/single-numeric-type/EntityType.t4 new file mode 100644 index 00000000..dc15c438 --- /dev/null +++ b/samples/ef-core/t4-templates/single-numeric-type/EntityType.t4 @@ -0,0 +1,189 @@ +<# // Sample Oracle T4 template to customize mapping one database column type to a specific .NET property with the name, Col1. The mapped .NET property, short, stores a superset of values of the mapped database type, NUMBER(1). #> + +<#@ template hostSpecific="true" #> +<#@ assembly name="Microsoft.EntityFrameworkCore" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Relational" #> +<#@ assembly name="Microsoft.Extensions.DependencyInjection.Abstractions" #> +<#@ parameter name="EntityType" type="Microsoft.EntityFrameworkCore.Metadata.IEntityType" #> +<#@ parameter name="Options" type="Microsoft.EntityFrameworkCore.Scaffolding.ModelCodeGenerationOptions" #> +<#@ parameter name="NamespaceHint" type="System.String" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.ComponentModel.DataAnnotations" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="Microsoft.EntityFrameworkCore" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Design" #> +<#@ import namespace="Microsoft.Extensions.DependencyInjection" #> +<# + if (EntityType.IsSimpleManyToManyJoinEntityType()) + { + // Don't scaffold these + return ""; + } + + var services = (IServiceProvider)Host; + var annotationCodeGenerator = services.GetRequiredService(); + var code = services.GetRequiredService(); + + var usings = new List + { + "System", + "System.Collections.Generic" + }; + + if (Options.UseDataAnnotations) + { + usings.Add("System.ComponentModel.DataAnnotations"); + usings.Add("System.ComponentModel.DataAnnotations.Schema"); + usings.Add("Microsoft.EntityFrameworkCore"); + } + + if (!string.IsNullOrEmpty(NamespaceHint)) + { +#> +namespace <#= NamespaceHint #>; + +<# + } + + if (!string.IsNullOrEmpty(EntityType.GetComment())) + { +#> +/// +/// <#= code.XmlComment(EntityType.GetComment()) #> +/// +<# + } + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in EntityType.GetDataAnnotations(annotationCodeGenerator)) + { +#> +<#= code.Fragment(dataAnnotation) #> +<# + } + } +#> +public partial class <#= EntityType.Name #> +{ +<# + var firstProperty = true; + foreach (var property in EntityType.GetProperties().OrderBy(p => p.GetColumnOrder() ?? -1)) + { + if (!firstProperty) + { + WriteLine(""); + } + + if (!string.IsNullOrEmpty(property.GetComment())) + { +#> + /// + /// <#= code.XmlComment(property.GetComment(), indent: 1) #> + /// +<# + } + + if (Options.UseDataAnnotations) + { + var dataAnnotations = property.GetDataAnnotations(annotationCodeGenerator) + .Where(a => !(a.Type == typeof(RequiredAttribute) && Options.UseNullableReferenceTypes && !property.ClrType.IsValueType)); + foreach (var dataAnnotation in dataAnnotations) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } + + // Make changes here to customize type mapping for specific properties. + Type clrType; + + if (property.Name == "Col1" // The name of the property that we want to customize the type-mapping for. + && property.GetColumnType() == "NUMBER(1)") // The store type of the property that we want to customize the type-mapping for. + { + clrType = Options.UseNullableReferenceTypes && property.IsNullable ? typeof(short?) : typeof(short); // Assign the custom CLR type we want. + } + else + { + clrType = property.ClrType; // Keep the default CLR Type. + } + + + usings.AddRange(code.GetRequiredUsings(clrType)); + + var needsNullable = Options.UseNullableReferenceTypes && property.IsNullable && !clrType.IsValueType; + var needsInitializer = Options.UseNullableReferenceTypes && !property.IsNullable && !clrType.IsValueType; +#> + public <#= code.Reference(clrType) #><#= needsNullable ? "?" : "" #> <#= property.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #> +<# + firstProperty = false; + } + + foreach (var navigation in EntityType.GetNavigations()) + { + WriteLine(""); + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in navigation.GetDataAnnotations(annotationCodeGenerator)) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } + + var targetType = navigation.TargetEntityType.Name; + if (navigation.IsCollection) + { +#> + public virtual ICollection<<#= targetType #>> <#= navigation.Name #> { get; set; } = new List<<#= targetType #>>(); +<# + } + else + { + var needsNullable = Options.UseNullableReferenceTypes && !(navigation.ForeignKey.IsRequired && navigation.IsOnDependent); + var needsInitializer = Options.UseNullableReferenceTypes && navigation.ForeignKey.IsRequired && navigation.IsOnDependent; +#> + public virtual <#= targetType #><#= needsNullable ? "?" : "" #> <#= navigation.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #> +<# + } + } + + foreach (var skipNavigation in EntityType.GetSkipNavigations()) + { + WriteLine(""); + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in skipNavigation.GetDataAnnotations(annotationCodeGenerator)) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } +#> + public virtual ICollection<<#= skipNavigation.TargetEntityType.Name #>> <#= skipNavigation.Name #> { get; set; } = new List<<#= skipNavigation.TargetEntityType.Name #>>(); +<# + } +#> +} +<# + var previousOutput = GenerationEnvironment; + GenerationEnvironment = new StringBuilder(); + + foreach (var ns in usings.Distinct().OrderBy(x => x, new NamespaceComparer())) + { +#> +using <#= ns #>; +<# + } + + WriteLine(""); + + GenerationEnvironment.Append(previousOutput); +#> diff --git a/samples/event-handler/src/RowUpdateEventHandler.vbproj b/samples/event-handler/src/RowUpdateEventHandler.vbproj deleted file mode 100644 index 22e5e31f..00000000 --- a/samples/event-handler/src/RowUpdateEventHandler.vbproj +++ /dev/null @@ -1,125 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {D6E5502F-88E6-4AB3-9BC9-B822F02F2726} - Debug - AnyCPU - - - - - RowUpdateEventHandler - v4.0 - - - None - JScript - Grid - IE50 - false - WinExe - Binary - On - Off - RowUpdateEventHandler - RowUpdateEventHandler.RowUpdate - - - WindowsFormsWithCustomSubMain - - - - - bin\ - RowUpdateEventHandler.xml - 285212672 - - - - - true - true - true - false - false - false - false - 1 - 42016,42017,42018,42019,42032 - full - - - bin\ - RowUpdateEventHandler.xml - 285212672 - - - - - false - true - false - true - false - false - false - 1 - 42016,42017,42018,42019,42032 - none - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.Drawing - - - System.Windows.Forms - - - System.XML - - - - - - - - - - - - - - - Code - - - Code - - - Form - - - RowUpdate.vb - - - - - - - - - - \ No newline at end of file diff --git a/samples/identity-access-mgmt/IAMOpenWithNewToken.cs b/samples/identity-access-mgmt/IAMOpenWithNewToken.cs new file mode 100644 index 00000000..62c88ff4 --- /dev/null +++ b/samples/identity-access-mgmt/IAMOpenWithNewToken.cs @@ -0,0 +1,330 @@ +/* + * This sample program utilizes the OCI .NET SDK to obtain a DB token. + * The token is then used to open a connection to an Oracle Database using IAM DB token + * authentication via the OracleConnection.Open() method. + * This sample also shows how to open a connection to an Oracle Database using IAM DB token + * authentication via the OracleConnection.OpenWithNewToken() method using a new/refreshed + * DB token before the initially obtained token expires. + * + * As a prerequisite, your cloud administrator must enable OCI IAM Single Sign-on with ADB. + * + * To run this sample, set the Oracle data source in the code below. If necessary, provide + * the TNS Admin directory location and wallet location. Set the OCI configuration profile + * if you are not using DEFAULT as its value. + * + * Requirements: + * .NET 5 runtime or later is required. + * + * Add the following NuGet packages to your .NET project: + * 1. OCI .NET SDK Version >= 29.4 + * Packages: + * OCI.DotNetSDK.Identitydataplane + * Includes dependency OCI.DotNetSDK.Common + * + * 2. ODP.NET Core version >= 3.21.41 + * Packages: + * Oracle.ManagedDataAccess.Core + * + * 3. Portable.BouncyCastle >= 1.9.0 + */ + +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using Oci.Common.Auth; +using Oci.IdentitydataplaneService; +using Oracle.ManagedDataAccess.Client; +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Security; + +namespace IAM_OpenWithNewToken +{ + class Program_bak + { + public static OracleAccessToken m_accessToken; + public static bool m_useOpenWithNewToken = false; + + public static void Main() + { + // Add the ADB instance connection info, such as net service name or TNS descriptor + string dataSource = @""; + + // Add the ADB tnsnames.ora and/or sqlnet.ora directory location here + // Not required if using walletless TLS + OracleConfiguration.TnsAdmin = @""; + + // Add the ADB wallet directory location here + // Not required if using walletless TLS + OracleConfiguration.WalletLocation = @""; + + // Later on, we will create an authentication provider that will use an OCI profile. + // Provide the profile name. We have used "DEFAULT" as the profile name in this + // sample. The configuration file is located at %HOMEDRIVE%%HOMEPATH%\.oci\config on + // Windows. On other operating systems, the location is ~/.oci/config + // Modify the profile name below if you use a different name. + // Refer to https://docs.cloud.oracle.com/en-us/iaas/Content/API/Concepts/sdkconfig.htm#SDK_and_CLI_Configuration_File to prepare a configuration file. + string profile = "DEFAULT"; + + // The public key that is needed for getting the DB token + string publicKey = null; + + // The private key that is needed for creating the OracleAccessToken + char[] privateKey = null; + + // The DB Token that is needed for creating the OracleAccessToken + string dbToken = null; + + // Generate the pair of private and public key + GenerateKeyPair(out publicKey, out privateKey); + + // Obtain the DB token using OCI .NET SDK + GetDBToken(publicKey, out dbToken, profile); + + // Create an OracleAccessToken + // Note: For security reasons, CreateAccessToken() clears out the passed dbToken + // and privatekey char[]s after storing them in a more secure format + CreateAccessToken(dbToken, privateKey); + + // Create a connection using IAM authentication and execute a SQL SELECT + DoWork(dataSource, dbToken, privateKey); + + // It is recommended that OpenWithNewToken method only be used in cases if the + // application is unable to or fails to provide the refreshed/updated DB token + // and private key through the token refresh call back for some reason. + // For this sample, we want to forcibly open a connection using + // OpenWithNewToken to show its use case without waiting for 1 hour. + // So, the function below that extracts the DB token expiration time and waits + // until 60 seconds before its expiration is commented out. + //WaitForTokenExpiration(dbToken); + + // Generate another pair of private and public key to be used for OpenWithNewToken + GenerateKeyPair(out publicKey, out privateKey); + + // Refresh/update the DB token from IAM + // Application does NOT need to get a new/refreshed db access token unless the + // previous DB token is about to expire + GetDBToken(publicKey, out dbToken, profile); + + // Set this to true for the connection to be opened using OpenWithNewToken + m_useOpenWithNewToken = true; + + // Create a connection using IAM authentication (with a refreshed token) and + // execute a SQL SELECT + DoWork(dataSource, dbToken, privateKey); + } + + public static void WaitForTokenExpiration(string dbToken) + { + // Getting DB token expiry time + OracleAccessToken.ParseDBToken(dbToken.ToCharArray(), out string subUserInNewDBToken, out DateTimeOffset dbTokenExpTime, out string jwkValInNewDBToken); + + // Get current time + DateTimeOffset currentTime = DateTimeOffset.Now.ToUniversalTime(); + + // Calculate time difference between DB expiry time and current time + TimeSpan timeDiff = TimeSpan.Zero; + if (dbTokenExpTime > currentTime) + timeDiff = dbTokenExpTime - currentTime; + + // Convert time difference into milliseconds + int waitTime = (int)timeDiff.TotalMilliseconds; + + // Wait until 60 seconds before the DB Token expires + waitTime -= 60000; + if (waitTime > 0) + Thread.Sleep(waitTime); + } + + public static void DoWork(string dataSource, string dbToken, char[] privateKey) + { + try + { + // The connection string to use DB tokens has a User Id set to "/" and + // an empty password. + string connection_string = "user id=/; data source=" + dataSource; + + // Create a connection object + OracleConnection con = new OracleConnection(connection_string); + + // Get the current user names associated with the connection object + GetCurrentUserName(con, dbToken, privateKey); + + // Dispose the connection object + con.Dispose(); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + public static void GetCurrentUserName(OracleConnection con, string dbToken, char[] privateKey) + { + // Provide the access token + con.AccessToken = m_accessToken; + + // Open the connection + if (!m_useOpenWithNewToken) + { + Console.Write("Using Open() to connect using IAM Authentication..."); + con.Open(); + Console.WriteLine("Successful!"); + } + else + { + Console.Write("Using OpenWithNewToken() to connect using IAM Authentication..."); + + // Note: OpenWithNewToken() call clears out the passed DB token and + // privateKey char[]s after storing them in a more secure format + con.OpenWithNewToken(dbToken.ToCharArray(), privateKey); + Console.WriteLine("Successful!"); + } + + // Create a command object + OracleCommand cmd = con.CreateCommand(); + + // Provide the SQL query to execute + cmd.CommandText = "select user from dual"; + + // Output the user name obtained from the SQL query + Console.WriteLine(cmd.ExecuteScalar()); + + // Dispose the command object + cmd.Dispose(); + } + + public static void CreateAccessToken(string dbToken, char[] privateKey) + { + try + { + // Create a new OracleAccessToken + m_accessToken = new OracleAccessToken(dbToken.ToCharArray(), privateKey); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + public static void GenerateKeyPair(out string publicKey, out char[] privateKey) + { + try + { + // Construct the RSACryptoServiceProvider object + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048); + + // Extract the public/private key pair + var rsaKeyPair = DotNetUtilities.GetRsaKeyPair(rsa); + + // Extract the private key + var pkcs8Gen = new Pkcs8Generator(rsaKeyPair.Private); + var pemObj = pkcs8Gen.Generate(); + + MemoryStream memoryStream = new MemoryStream(); + TextWriter streamWriter = new StreamWriter(memoryStream); + PemWriter pemWriter = new PemWriter(streamWriter); + pemWriter.WriteObject(pemObj); + streamWriter.Flush(); + + // Extract byte array from memory stream + byte[] bytearray = memoryStream.GetBuffer(); + + // Convert byte array into char array + privateKey = Encoding.ASCII.GetChars(bytearray); + + // Clear byte array + Array.Clear(bytearray, 0, bytearray.Length); + + // Dispose stream writer and memory stream + streamWriter.Dispose(); + memoryStream.Dispose(); + + // Extract the public key + TextWriter stringWriter = new StringWriter(); + pemWriter = new PemWriter(stringWriter); + pemWriter.WriteObject(rsaKeyPair.Public); + stringWriter.Flush(); + publicKey = stringWriter.ToString(); + + // Display the extracted public key + Console.WriteLine("public key, {0}", publicKey); + + // Display the extracted private key + foreach (char ch in privateKey) + { + Console.Write(ch); + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + public static string GetDBToken(string publicKey, out string dbToken, in string profile) + { + try + { + // Create a dependent object with scope and public key information + var generateScopedAccessTokenDetails = new Oci.IdentitydataplaneService.Models.GenerateScopedAccessTokenDetails + { + Scope = "urn:oracle:db::id::*", + PublicKey = publicKey + }; + + // Create a request using the dependent object + var generateScopedAccessTokenRequest = new Oci.IdentitydataplaneService.Requests.GenerateScopedAccessTokenRequest + { + GenerateScopedAccessTokenDetails = generateScopedAccessTokenDetails + }; + + // Create authentication provider using designated OCI configuration profile + var provider = new ConfigFileAuthenticationDetailsProvider(profile); + + // Create a service client and send the request + using (var client = new DataplaneClient(provider)) + { + // Request a DB token + var response = client.GenerateScopedAccessToken(generateScopedAccessTokenRequest).Result; + + // Retrieve value from the response + dbToken = response.SecurityToken.Token; + + // Display retrived DB token + Console.WriteLine("-----BEGIN Db Token-----\n{0}\n-----END Db Token-----", dbToken); + + return dbToken; + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + } +} + +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/lob/Sample1.csproj b/samples/lob/Sample1.csproj deleted file mode 100644 index bca69f1e..00000000 --- a/samples/lob/Sample1.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {EEC57E74-239F-4F4B-A2DB-6464D74F61B6} - Debug - AnyCPU - - - - - Sample1 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample1 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/lob/Sample2.csproj b/samples/lob/Sample2.csproj deleted file mode 100644 index 4d529e84..00000000 --- a/samples/lob/Sample2.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {0658416D-F576-41C7-91CB-8A12B1EABA22} - Debug - AnyCPU - - - - - Sample2 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample2 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/lob/Sample3.csproj b/samples/lob/Sample3.csproj deleted file mode 100644 index 76939b28..00000000 --- a/samples/lob/Sample3.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {5AF5FD57-2EE6-458F-9C2A-5D35605B4DE0} - Debug - AnyCPU - - - - - Sample3 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample3 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/lob/Sample4.csproj b/samples/lob/Sample4.csproj deleted file mode 100644 index a33a1085..00000000 --- a/samples/lob/Sample4.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {4A082E2B-FB05-4102-8509-170AAD71784C} - Debug - AnyCPU - - - - - Sample4 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample4 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/lob/Sample5.csproj b/samples/lob/Sample5.csproj deleted file mode 100644 index 31fe6b00..00000000 --- a/samples/lob/Sample5.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {F89DBAC6-42FA-407B-A732-E9965DD7316F} - Debug - AnyCPU - - - - - Sample5 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample5 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/lob/Sample6.csproj b/samples/lob/Sample6.csproj deleted file mode 100644 index 3fce7749..00000000 --- a/samples/lob/Sample6.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {612F9FEA-9024-4426-A308-47C2A88E96E1} - Debug - AnyCPU - - - - - Sample6 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample6 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/lob/Sample7.csproj b/samples/lob/Sample7.csproj deleted file mode 100644 index 77324ef8..00000000 --- a/samples/lob/Sample7.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {F07A0DDA-063C-4A03-87F7-557F7E4D9DC9} - Debug - AnyCPU - - - - - Sample7 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample7 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/lob/bfile/src/AccessBfile.vbproj b/samples/lob/bfile/src/AccessBfile.vbproj deleted file mode 100644 index 7eac7bc1..00000000 --- a/samples/lob/bfile/src/AccessBfile.vbproj +++ /dev/null @@ -1,115 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {C3ADB2E3-4750-4F00-82E7-115478A4D1CA} - Debug - AnyCPU - - - - - AccessBfile - v4.0 - - - None - JScript - Grid - IE50 - false - WinExe - Binary - On - Off - AccessBfile - AccessBfile.BFileFrm - - - WindowsFormsWithCustomSubMain - - - - - bin\ - AccessBfile.xml - 285212672 - - - - - true - true - true - false - false - false - false - 1 - 42016,42017,42018,42019,42032 - full - - - bin\ - AccessBfile.xml - 285212672 - - - - - false - true - false - true - false - false - false - 1 - 42016,42017,42018,42019,42032 - none - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.Drawing - - - System.Windows.Forms - - - - - - - - - - - - - - Form - - - Bfile.vb - - - - - - - - - - \ No newline at end of file diff --git a/samples/opentelemetry/opentelemetry.cs b/samples/opentelemetry/opentelemetry.cs new file mode 100644 index 00000000..92840299 --- /dev/null +++ b/samples/opentelemetry/opentelemetry.cs @@ -0,0 +1,85 @@ +// ODP.NET OpenTelemetry Demo +// This sample demonstrates using managed ODP.NET or ODP.NET Core with OpenTelemetry using the HR schema. +// To setup, add NuGet packages: Oracle.ManagedDataAccess.OpenTelemetry, OpenTelemetry, and an OpenTelemetry exporter. +// This sample is configured to use the Console Exporter (OpenTelemetry.Exporter.Console), but can be modified to another exporter. +// Provide the Oracle database password and data source information for the connection string. + +using System.Diagnostics; +using OpenTelemetry; // for Sdk +using OpenTelemetry.Trace; // for TracerProvider and TracerProviderBuilder +using Oracle.ManagedDataAccess.Client; // for ODP.NET +using Oracle.ManagedDataAccess.OpenTelemetry; // for ODP.NET OpenTelemetry + +class ODP_OTel_Demo +{ + static TracerProvider tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddOracleDataProviderInstrumentation(o => // ODP.NET OpenTelemetry extension method + { + o.EnableConnectionLevelAttributes = true; + o.RecordException = true; + o.InstrumentOracleDataReaderRead = true; + o.SetDbStatementForText = true; + }) + .AddSource("ODP.NET App") + .AddConsoleExporter() // OpenTelemetry.Exporter.Console NuGet package extension method + //.AddZipkinExporter() // OpenTelemetry.Exporter.Zipkin NuGet package extension method + .Build()!; + + static ActivitySource activitySource = new ActivitySource("ODP.NET App"); + + static string conString = @"User Id=hr;Password=;Data Source=;"; + + static void Main() + { + using (OracleConnection con = new OracleConnection(conString)) + { + using (OracleCommand cmd = con.CreateCommand()) + { + try + { + con.Open(); + cmd.CommandText = "select * from employees"; + + // Start OpenTelemetry activity + using (Activity activity = activitySource.StartActivity("Retrieve data")!) + { + OracleDataReader reader = cmd.ExecuteReader(); + while (reader.Read()) + { + // Use query results + } + reader.Dispose(); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + } + } +} + +/****************************************************************************** +* The MIT License (MIT) +* +* Copyright (c) 2015, 2023 Oracle +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: + +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. + +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. + *****************************************************************************/ diff --git a/samples/pipelining/no-pipelining-and-sync.cs b/samples/pipelining/no-pipelining-and-sync.cs new file mode 100644 index 00000000..c80de923 --- /dev/null +++ b/samples/pipelining/no-pipelining-and-sync.cs @@ -0,0 +1,87 @@ +using Oracle.ManagedDataAccess.Client; +using System.Threading.Tasks; +using System.Threading; +using System; + +// This code sample demonstrates using synchronous ODP.NET (managed or core) without pipelining. +// It times opening a connection and several query executions. +// To run this app, add your database's HR schema User Id, Password, and Data Source values +// with ODP.NET 23ai or higher connecting to an Oracle Database 23ai or higher. + +class ODPNET_Sync_And_No_Pipelining +{ + static void Main() + { + // Add password and data source to connect to your Oracle database + string conString = "User Id=hr;Password=;Data Source=;"; + + using (OracleConnection con = new OracleConnection(conString)) + { + string cmdText1 = "SELECT * FROM EMPLOYEES"; + string cmdText2 = "SELECT * FROM DEPARTMENTS"; + string cmdText3 = "SELECT * FROM JOBS"; + + OracleCommand cmd1 = new OracleCommand(cmdText1, con); + OracleCommand cmd2 = new OracleCommand(cmdText2, con); + OracleCommand cmd3 = new OracleCommand(cmdText3, con); + + // Measure how long connection open takes + DateTime start_time = DateTime.Now; + con.Open(); + DateTime end_time_open = DateTime.Now; + + // Simulate an operation that takes one second + Thread.Sleep(1000); + + // Measure time for query executions + DateTime start_time_query = DateTime.Now; + cmd1.ExecuteNonQuery(); + cmd2.ExecuteNonQuery(); + cmd3.ExecuteNonQuery(); + + // Simulate an operation that takes one second + Thread.Sleep(1000); + + // Record time all the synchronous operations took plus the sleep time + DateTime end_time_all = DateTime.Now; + + // Calculate connection open time + TimeSpan ts_open = end_time_open - start_time; + double ts_open1 = Math.Round(ts_open.TotalSeconds, 2); + Console.WriteLine("Synchronous connection open time: " + ts_open1 + " seconds"); + + // Calculate SQL executions time + TimeSpan ts_sql = end_time_all - start_time_query; + double ts_sql1 = Math.Round(ts_sql.TotalSeconds, 2); + Console.WriteLine("Synchronous query execution time: " + ts_sql1 + " seconds"); + + // Calculate overall ODP.NET operation time + TimeSpan ts_all = end_time_all - start_time; + double ts_all1 = Math.Round(ts_all.TotalSeconds, 2); + Console.WriteLine("Synchronous operation total time: " + ts_all1 + " seconds"); + + cmd1.Dispose(); + cmd2.Dispose(); + cmd3.Dispose(); + } + } +} + +/* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/pipelining/pipelining-and-async.cs b/samples/pipelining/pipelining-and-async.cs new file mode 100644 index 00000000..abc85528 --- /dev/null +++ b/samples/pipelining/pipelining-and-async.cs @@ -0,0 +1,105 @@ +using Oracle.ManagedDataAccess.Client; +using System.Threading.Tasks; +using System.Threading; +using System; + +// This code sample demonstrates using asynchronous ODP.NET (managed or core) with pipelining. +// It times opening a connection and several query executions. +// To run this app, add your database's HR schema User Id, Password, and Data Source values +// with ODP.NET 23ai or higher connecting to an Oracle Database 23ai or higher. + +class ODPNET_Async_Pipelining +{ + public static async Task Main() + { + // Add password and data source to connect to your Oracle database + string conString = "User Id=hr;Password=;Data Source=;"; + + //Enable pipelining + OracleConfiguration.Pipelining = true; + + using (OracleConnection con = new OracleConnection(conString)) + { + string cmdText1 = "SELECT * FROM EMPLOYEES"; + string cmdText2 = "SELECT * FROM DEPARTMENTS"; + string cmdText3 = "SELECT * FROM JOBS"; + + OracleCommand cmd1 = new OracleCommand(cmdText1, con); + OracleCommand cmd2 = new OracleCommand(cmdText2, con); + OracleCommand cmd3 = new OracleCommand(cmdText3, con); + + // Measure how long async connection open takes + DateTime start_time = DateTime.Now; + Task task = con.OpenAsync(); + DateTime end_time_open = DateTime.Now; + + // Simulate an operation that takes one second + Thread.Sleep(1000); + + // Retrieve open connection with "await" + await task; + + // Measure time for asynchronous query execution calls + DateTime start_time_query = DateTime.Now; + Task task1 = cmd1.ExecuteNonQueryAsync(); + Task task2 = cmd2.ExecuteNonQueryAsync(); + Task task3 = cmd3.ExecuteNonQueryAsync(); + + // Measure time async query initiations took + DateTime end_time_query = DateTime.Now; + + // Simulate an operation that takes one second + Thread.Sleep(1000); + + await task1; + await task2; + await task3; + + // Measure time all the async operations took plus sleep time + DateTime end_time_all = DateTime.Now; + + // Calculate connection open time + TimeSpan ts_open = end_time_open - start_time; + double ts_open1 = Math.Round(ts_open.TotalSeconds, 2); + Console.WriteLine("Asynchronous connection open time: " + ts_open1 + " seconds"); + + // Calculate queries initiation time + TimeSpan ts_initiate_sql = end_time_query - start_time_query; + double ts_sql1 = Math.Round(ts_initiate_sql.TotalSeconds, 2); + Console.WriteLine("Asynchronous and pipelining query initiation time: " + ts_sql1 + " seconds"); + + // Calculate SQL executions time + TimeSpan ts_sql = end_time_all - start_time_query; + double ts_sql2 = Math.Round(ts_sql.TotalSeconds, 2); + Console.WriteLine("Asynchronous and pipelining query execution time: " + ts_sql2 + " seconds"); + + // Calculate overall ODP.NET operation time + TimeSpan ts_all = end_time_all - start_time; + double ts_all1 = Math.Round(ts_all.TotalSeconds, 2); + Console.WriteLine("Asynchronous and pipelining operations total time: " + ts_all1 + " seconds"); + + cmd1.Dispose(); + cmd2.Dispose(); + cmd3.Dispose(); + } + } +} + +/* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/ref-cursor/Sample1.csproj b/samples/ref-cursor/Sample1.csproj deleted file mode 100644 index bca69f1e..00000000 --- a/samples/ref-cursor/Sample1.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {EEC57E74-239F-4F4B-A2DB-6464D74F61B6} - Debug - AnyCPU - - - - - Sample1 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample1 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/ref-cursor/Sample2.csproj b/samples/ref-cursor/Sample2.csproj deleted file mode 100644 index ca3fc27f..00000000 --- a/samples/ref-cursor/Sample2.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {9C4A9AED-731B-46D0-8B3D-1D7EFE11B2BB} - Debug - AnyCPU - - - - - Sample2 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample2 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/ref-cursor/Sample3.csproj b/samples/ref-cursor/Sample3.csproj deleted file mode 100644 index 3e338710..00000000 --- a/samples/ref-cursor/Sample3.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {C8695F10-D39E-41FE-A460-3490BBEEAA87} - Debug - AnyCPU - - - - - Sample3 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample3 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/ref-cursor/Sample4.csproj b/samples/ref-cursor/Sample4.csproj deleted file mode 100644 index 5c141ecb..00000000 --- a/samples/ref-cursor/Sample4.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {BDBE534E-7204-4B36-AB22-35A2925DADEE} - Debug - AnyCPU - - - - - Sample4 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample4 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/ref-cursor/Sample5.csproj b/samples/ref-cursor/Sample5.csproj deleted file mode 100644 index 02a857b4..00000000 --- a/samples/ref-cursor/Sample5.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {7164A748-0B46-41F1-990B-B42975F74E7B} - Debug - AnyCPU - - - - - Sample5 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample5 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/ref-cursor/Sample6.csproj b/samples/ref-cursor/Sample6.csproj deleted file mode 100644 index e41c0dc6..00000000 --- a/samples/ref-cursor/Sample6.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {F266E45C-39EF-4F98-BE0E-03DC6D3A5191} - Debug - AnyCPU - - - - - Sample6 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample6 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/ref-cursor/Sample7.csproj b/samples/ref-cursor/Sample7.csproj deleted file mode 100644 index c8c5b8f5..00000000 --- a/samples/ref-cursor/Sample7.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {BCFA80E7-EE37-4652-8FF8-3DA8ED738579} - Debug - AnyCPU - - - - - Sample7 - v4.0 - - - JScript - Grid - IE50 - false - Exe - Sample7 - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/statement-cache/StatementCache.cs b/samples/statement-cache/StatementCache.cs index 32ea19be..5d4fdefb 100644 --- a/samples/statement-cache/StatementCache.cs +++ b/samples/statement-cache/StatementCache.cs @@ -1,22 +1,3 @@ -/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ - -/****************************************************************************** - * - * You may not use the identified files except in compliance with The MIT - * License (the "License.") - * - * You may obtain a copy of the License at - * https://github.com/oracle/Oracle.NET/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *****************************************************************************/ - using System; using System.Data; using System.Text; @@ -152,3 +133,22 @@ public static OracleConnection Connect(string connectStr) } } } + +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/statement-cache/StatementCache.csproj b/samples/statement-cache/StatementCache.csproj deleted file mode 100644 index bb75e788..00000000 --- a/samples/statement-cache/StatementCache.csproj +++ /dev/null @@ -1,105 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {8E38C960-FF1E-4850-8720-CDC50B9729BC} - Debug - AnyCPU - - - - - StatementCache - v4.0 - - - JScript - Grid - IE50 - false - Exe - StatementCache - OnBuildSuccess - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - - - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - false - - - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - System.XML - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/transaction/enlist/psfEnlistTransaction.csproj b/samples/transaction/enlist/psfEnlistTransaction.csproj deleted file mode 100644 index 037db492..00000000 --- a/samples/transaction/enlist/psfEnlistTransaction.csproj +++ /dev/null @@ -1,124 +0,0 @@ - - - - Local - 8.0.30319 - 2.0 - {8738626F-6460-4138-82AD-4EEB0FFE6D25} - Debug - AnyCPU - - - psfEnlistTransaction - - JScript - Grid - IE50 - false - Exe - psfEnlistTransaction - - - - v4.0 - - - 0.0 - - http://localhost/psfEnlistTransaction/ - true - Web - true - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - true - false - true - - - bin\Debug\ - false - 285212672 - false - - DEBUG;TRACE - - true - 4096 - false - false - false - false - 4 - full - prompt - AllRules.ruleset - - - bin\Release\ - false - 285212672 - false - - TRACE - - false - 4096 - true - false - false - false - 4 - none - prompt - AllRules.ruleset - - - - ..\..\bin\Release\4.0\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - - System.XML - - - - - Code - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - - - - \ No newline at end of file diff --git a/samples/transaction/savepoint/src/Savepoint.csproj b/samples/transaction/savepoint/src/Savepoint.csproj deleted file mode 100644 index 97b4c742..00000000 --- a/samples/transaction/savepoint/src/Savepoint.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {F1D50CF2-7B21-4C20-8572-9613ADD4AEA2} - Debug - AnyCPU - - - - - SavepointSample - v4.0 - - - JScript - Grid - IE50 - false - Exe - Savepoint - - - - - - - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - false - false - false - 4 - full - prompt - - - bin\Release\ - false - 285212672 - false - - - TRACE - - - false - 4096 - true - false - false - false - 4 - none - prompt - - - - Oracle.ManagedDataAccess - ..\..\..\..\odp.net\bin\4\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - - - Code - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/samples/transaction/transaction-scope/psfTxnScope.csproj b/samples/transaction/transaction-scope/psfTxnScope.csproj deleted file mode 100644 index 474856a2..00000000 --- a/samples/transaction/transaction-scope/psfTxnScope.csproj +++ /dev/null @@ -1,124 +0,0 @@ - - - - Local - 8.0.30319 - 2.0 - {8738626F-6460-4138-82AD-4EEB0FFE6D25} - Debug - AnyCPU - - - psfTxnScope - - JScript - Grid - IE50 - false - Exe - psfTxnScope - - - - v4.0 - - - 0.0 - - http://localhost/psfTxnScope/ - true - Web - true - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - true - false - true - - - bin\Debug\ - false - 285212672 - false - - DEBUG;TRACE - - true - 4096 - false - false - false - false - 4 - full - prompt - AllRules.ruleset - - - bin\Release\ - false - 285212672 - false - - TRACE - - false - 4096 - true - false - false - false - 4 - none - prompt - AllRules.ruleset - - - - ..\..\bin\Release\4.0\Oracle.ManagedDataAccess.dll - - - System - - - System.Data - - - - System.XML - - - - - Code - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - - - - diff --git a/samples/udt/Nested-Table.cs b/samples/udt/Nested-Table.cs new file mode 100644 index 00000000..7bb3ddd1 --- /dev/null +++ b/samples/udt/Nested-Table.cs @@ -0,0 +1,459 @@ +/* +This sample demonstrates how to map, fetch, and manipulate + a nested table of UDTs that has an inheritance hierarchy + (i.e. parent and child types). This sample can use managed + ODP.NET or ODP.NET Core. + +Database schema setup scripts: + +1. Connect to HR or another similar schema. +2. Run the following SQL scripts to create a person type, + a student type that inherits from person type, a nested + table of person types, and a table with a nested table column. + +drop table odp_nt_sample_person_rel_tab; +drop type odp_nt_sample_person_coll_type; +drop type odp_nt_sample_student_type; +drop type odp_nt_sample_person_type; + +create type odp_nt_sample_person_type as object + (name varchar2(30), address varchar2(60), age number(3)) NOT FINAL; +/ +create type odp_nt_sample_student_type under odp_nt_sample_person_type + (dept_id number(2), major varchar2(20)); +/ +create type odp_nt_sample_person_coll_type as + table of odp_nt_sample_person_type; +/ +create table odp_nt_sample_person_rel_tab + (col1 odp_nt_sample_person_coll_type) nested table col1 store as nt_s; + +*/ + +using System; +using System.Data; +using System.Collections; +using Oracle.ManagedDataAccess.Client; +using Oracle.ManagedDataAccess.Types; + +class NestedTableSample +{ + static void Main(string[] args) + { + // Enter user id, password, and Oracle data source (i.e. net service name, EZ Connect, etc.) + string constr = "user id=;password=;data source="; + + string sql1 = "insert into odp_nt_sample_person_rel_tab values(:param)"; + string sql2 = "select col1 from odp_nt_sample_person_rel_tab"; + + // Create a new Person object + Person p1 = new Person(); + p1.Name = "John"; + p1.Address = "Address 1"; + p1.Age = 20; + + // Create a new Student object + Student s1 = new Student(); + s1.Name = "Jim"; + s1.Address = "Address 2"; + s1.Age = 25; + s1.Major = "Physics"; + + // Create a second Student object + Student s2 = new Student(); + s2.Name = "Alex"; + s2.Address = "Address 3"; + s2.Age = 21; + s2.Major = "Math"; + + // Create a new Person array + Person[] pa = new Person[] { p1, s1 }; + + OracleConnection con = null; + OracleCommand cmd = null; + OracleDataReader reader = null; + + try + { + // Establish a connection to Oracle DB + con = new OracleConnection(constr); + con.Open(); + + cmd = new OracleCommand(sql1, con); + cmd.CommandText = sql1; + + OracleParameter param = new OracleParameter(); + param.OracleDbType = OracleDbType.Array; + param.Direction = ParameterDirection.Input; + + // Note: The UdtTypeName is case-senstive + param.UdtTypeName = "ODP_NT_SAMPLE_PERSON_COLL_TYPE"; + param.Value = pa; + cmd.Parameters.Add(param); + + // Insert a nested table of (person, student) into the table column + cmd.ExecuteNonQuery(); + + // Modify some elements in Person array + pa[1].Address = "Modified Address"; + pa[1].Age = pa[1].Age + 1; + + // Add/Remove some elements by converting the Person[] to an ArrayList + ArrayList list = new ArrayList(pa); + + // Remove the first element + list.RemoveAt(0); + + // Add the second student + list.Add(s2); + pa = (Person[])list.ToArray(typeof(Person)); + + param.Value = pa; + + // The array now has two students. + // Insert a nested table of (student, student) into the table column. + cmd.ExecuteNonQuery(); + + cmd.CommandText = sql2; + cmd.CommandType = CommandType.Text; + reader = cmd.ExecuteReader(); + + // Fetch each row + int rowCount = 1; + while (reader.Read()) + { + // Fetch the array and print out each element. + // Observe that four new elements were inserted with this app. + Person[] p = (Person[])reader.GetValue(0); + for (int i = 0; i < p.Length; i++) + Console.WriteLine("Row {0}, Person[{1}]: {2} ", rowCount, i, p.GetValue(i)); + rowCount++; + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + // Clean up + if (reader != null) + reader.Dispose(); + if (cmd != null) + cmd.Dispose(); + if (con != null) + con.Dispose(); + } + } +} + +// Person Class +// An instance of a Person class represents an ODP_NT_SAMPLE_PERSON_TYPE object. +// A custom type must implement INullable and IOracleCustomType interfaces. +public class Person : INullable, IOracleCustomType +{ + private bool m_bIsNull; // Whether the Person object is NULL + private string m_name; // "NAME" attribute + private OracleString m_address; // "ADDRESS" attribute + private int? m_age; // "AGE" attribute + + // Implementation of INullable.IsNull + public virtual bool IsNull + { + get + { + return m_bIsNull; + } + } + + // Person.Null is used to return a NULL Person object. + public static Person Null + { + get + { + Person p = new Person(); + p.m_bIsNull = true; + return p; + } + } + + // Specify the OracleObjectMappingAttribute to map "Name" to "NAME". + [OracleObjectMappingAttribute("NAME")] + // The mapping can also be specified using attribute index 0. + // [OracleObjectMappingAttribute(0)] + public string Name + { + get + { + return m_name; + } + set + { + m_name = value; + } + } + + // Specify the OracleObjectMappingAttribute to map "Address" to "ADDRESS". + [OracleObjectMappingAttribute("ADDRESS")] + // The mapping can also be specified using attribute index 1. + // [OracleObjectMappingAttribute(1)] + public OracleString Address + { + get + { + return m_address; + } + set + { + m_address = value; + } + } + + // Specify the OracleObjectMappingAttribute to map "Age" to "AGE". + [OracleObjectMappingAttribute("AGE")] + // The mapping can also be specified using attribute index 2. + // [OracleObjectMappingAttribute(2)] + + public int? Age + + { + get + { + return m_age; + } + set + { + m_age = value; + } + } + + // Implementation of IOracleCustomType.FromCustomObject() + public virtual void FromCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Custom Type to Oracle Object + + // Set the "NAME" attribute. + // By default the "NAME" attribute will be set to NULL. + if (m_name != null) + { + OracleUdt.SetValue(con, pUdt, "NAME", m_name); + // The "NAME" attribute can also be accessed by specifying index 0. + // OracleUdt.SetValue(con, pUdt, 0, m_name); + } + + // Set the "ADDRESS" attribute. + // By default the "ADDRESS" attribute will be set to NULL. + if (!m_address.IsNull) + { + OracleUdt.SetValue(con, pUdt, "ADDRESS", m_address); + // The "ADDRESS" attribute can also be accessed by specifying index 1. + // OracleUdt.SetValue(con, pUdt, 1, m_address); + } + + // Set the "AGE" attribute. + // By default the "AGE" attribute will be set to NULL. + if (m_age != null) + { + OracleUdt.SetValue(con, pUdt, "AGE", m_age); + // The "AGE attribute can also be accessed by specifying index 2. + // OracleUdt.SetValue(con, pUdt, 2, m_age); + } + } + + // Implementation of IOracleCustomType.ToCustomObject() + public virtual void ToCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Oracle Object to a Custom Type + + // Get the "NAME" attribute. + // If the "NAME" attribute is NULL, then null will be returned. + m_name = (string)OracleUdt.GetValue(con, pUdt, "NAME"); + // The "NAME" attribute can also be accessed by specifying index 0. + // m_name = (string)OracleUdt.GetValue(con, pUdt, 0); + + // Get the "ADDRESS" attribute. + // If the "ADDRESS" attribute is NULL, then OracleString.Null will be returned. + m_address = (OracleString)OracleUdt.GetValue(con, pUdt, "ADDRESS"); + // The "ADDRESS" attribute can also be accessed by specifying index 1. + // m_address = (OracleString)OracleUdt.GetValue(con, pUdt, 1); + + // Get the "AGE" attribute. + // If the "AGE" attribute is NULL, then null will be returned. + m_age = (int?)OracleUdt.GetValue(con, pUdt, "AGE"); + // The "AGE" attribute can also be accessed by specifying index 2. + // m_age = (int?)OracleUdt.GetValue(con, pUdt, 2); + } + + public override string ToString() + { + // Return a string representation of the custom object + if (m_bIsNull) + return "Person.Null"; + else + { + string name = (m_name == null) ? "NULL" : m_name; + string address = (m_address.IsNull) ? "NULL" : m_address.Value; + string age = (m_age == null)? "NULL" : m_age.ToString(); + + return "Person(" + name + ", " + address + ", " + age + ")"; + } + } +} + +// PersonFactory Class +// An instance of the PersonFactory class is used to create Person objects. +[OracleCustomTypeMappingAttribute("ODP_NT_SAMPLE_PERSON_TYPE")] +public class PersonFactory : IOracleCustomTypeFactory +{ + // Implementation of IOracleCustomTypeFactory.CreateObject() + public IOracleCustomType CreateObject() + { + // Return a new custom object + return new Person(); + } +} + +// Student Class +// A Student class instance represents an ODP_NT_SAMPLE_STUDENT_TYPE object. +// Note: We do not map the "DEPT_ID" attribute (attribute index 3) so it +// will always be NULL. A custom type must implement INullable and +// IOracleCustomType interfaces. +public class Student : Person, INullable, IOracleCustomType +{ + private bool m_bIsNull; // Whether the Student object is NULL + private string m_major; // "MAJOR" attribute + + // Implementation of INullable.IsNull + public override bool IsNull + { + get + { + return m_bIsNull; + } + } + + // Student.Null is used to return a NULL Student object. + public new static Student Null + { + get + { + Student s = new Student(); + s.m_bIsNull = true; + return s; + } + } + + // Specify the OracleObjectMappingAttribute to map "Major" to "MAJOR". + [OracleObjectMappingAttribute("MAJOR")] + // The mapping can also be specified using attribute index 4. + // [OracleObjectMappingAttribute(4)] + public string Major + { + get + { + return m_major; + } + set + { + m_major = value; + } + } + + // Implementation of IOracleCustomType.FromCustomObject() + public override void FromCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Custom Type to Oracle Object. + // Invoke the base class conversion method. + base.FromCustomObject(con, pUdt); + + // Set the "MAJOR" attribute. + // By default, the "MAJOR" attribute will be set to NULL. + if (m_major != null) + OracleUdt.SetValue(con, pUdt, "MAJOR", m_major); + + // The "MAJOR" attribute can also be accessed by specifying index 4. + // OracleUdt.SetValue(con, pUdt, 4, m_major); + } + + // Implementation of IOracleCustomType.ToCustomObject() + public override void ToCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Oracle Object to a Custom Type. + // Invoke the base class conversion method. + base.ToCustomObject(con, pUdt); + + // Get the "MAJOR" attribute. + // If the "MAJOR" attribute is NULL, then "null" will be returned. + m_major = (string)OracleUdt.GetValue(con, pUdt, "MAJOR"); + // The "MAJOR" attribute can also be accessed by specifying index 4. + // m_major = (string)OracleUdt.GetValue(con, pUdt, 4); + } + + public override string ToString() + { + // Return a string representation of the custom object + if (m_bIsNull) + { + return "Student.Null"; + } + else + { + string name = (Name == null) ? "NULL" : Name; + string address = (Address.IsNull) ? "NULL" : Address.Value; + string age = (Age == null) ? "NULL" : Age.ToString(); + string major = (m_major == null) ? "NULL" : m_major; + + return "Student(" + name + ", " + address + ", " + age + ", " + major + ")"; + } + } +} + +// StudentFactory Class +// An instance of the StudentFactory class is used to create Student objects. +[OracleCustomTypeMappingAttribute("ODP_NT_SAMPLE_STUDENT_TYPE")] +public class StudentFactory : IOracleCustomTypeFactory +{ + // Implementation of IOracleCustomTypeFactory.CreateObject() + public IOracleCustomType CreateObject() + { + // Return a new custom object + return new Student(); + } +} + +// PersonArrayFactory Class +// An instance of the PersonArrayFactory class is used to create Person array. +[OracleCustomTypeMappingAttribute("ODP_NT_SAMPLE_PERSON_COLL_TYPE")] +public class PersonArrayFactory : IOracleArrayTypeFactory +{ + // IOracleArrayTypeFactory Inteface + public Array CreateArray(int numElems) + { + return new Person[numElems]; + } + + public Array CreateStatusArray(int numElems) + { + // An OracleUdtStatus[] is not required to store null status information. + return null; + } +} + +/* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/udt/Object-UDT.cs b/samples/udt/Object-UDT.cs new file mode 100644 index 00000000..7c1396d8 --- /dev/null +++ b/samples/udt/Object-UDT.cs @@ -0,0 +1,346 @@ +/* +This sample demonstrates how to map, fetch, and + manipulate an Oracle user-defined type (UDT) as + a .NET custom object. This sample can use managed + ODP.NET or ODP.NET Core. + +Database schema setup scripts: + +1. Connect to HR or another similar schema. +2. Run the following SQL scripts to create a person + UDT, a contacts table with a person UDT column, and + a stored procedure that updates a UDT property. + +drop procedure odp_obj1_sample_upd_contacts; +drop table odp_obj1_sample_contacts; +drop type odp_obj1_sample_person_type; + +create type odp_obj1_sample_person_type as object + (name varchar2(30), address varchar2(60), age number(3)) NOT FINAL; +/ + +create table odp_obj1_sample_contacts ( + contact odp_obj1_sample_person_type, + contact_phone varchar2(20)); + +create procedure odp_obj1_sample_upd_contacts( + param1 IN OUT odp_obj1_sample_person_type, + param2 IN varchar2) as + begin + param1.age := param1.age + 1; + insert into odp_obj1_sample_contacts values(param1,param2); + end; +/ + +*/ + +using System; +using System.Data; +using Oracle.ManagedDataAccess.Client; +using Oracle.ManagedDataAccess.Types; + +class ObjectUDT +{ + static void Main(string[] args) + { + // Enter user id, password, and Oracle data source (i.e. net service name, EZ Connect, etc.) + string constr = "user id=;password=;data source="; + + string sql1 = "odp_obj1_sample_upd_contacts"; + string sql2 = "select c.contact from odp_obj1_sample_contacts c"; + + // Create a new Person object + Person p1 = new Person(); + p1.Name = "John"; + p1.Address = "Address 1"; + p1.Age = 20; + + OracleConnection con = null; + OracleCommand cmd = null; + + try + { + // Establish a connection to Oracle database + con = new OracleConnection(constr); + con.Open(); + cmd = new OracleCommand(sql1, con); + + try + { + // Insert Person object into a database and update object + // using a stored procedure + cmd.CommandType = CommandType.StoredProcedure; + OracleParameter param1 = new OracleParameter(); + + param1.OracleDbType = OracleDbType.Object; + param1.Direction = ParameterDirection.InputOutput; + + // Note: The UdtTypeName is case-senstive + param1.UdtTypeName = "ODP_OBJ1_SAMPLE_PERSON_TYPE"; + param1.Value = p1; + + cmd.Parameters.Add(param1); + + OracleParameter param2 = new OracleParameter(); + param2.OracleDbType = OracleDbType.Varchar2; + param2.Direction = ParameterDirection.Input; + param2.Value = "1-800-555-4412"; + + cmd.Parameters.Add(param2); + + // Insert the UDT into the table + cmd.ExecuteNonQuery(); + + // Print out the updated Person object + Console.WriteLine("Updated Person: " + param1.Value); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + // Clean up + if (cmd != null) + cmd.Parameters.Clear(); + } + + OracleDataReader reader = null; + try + { + // Retrieve the updated objects from the database table + cmd.CommandText = sql2; + cmd.CommandType = CommandType.Text; + reader = cmd.ExecuteReader(); + + // Fetch each row + int rowCount = 1; + while (reader.Read()) + { + // Fetch the objects as a custom type + Person p; + if (reader.IsDBNull(0)) + p = Person.Null; + else + p = (Person)reader.GetValue(0); + + Console.WriteLine("Row {0}: {1}", rowCount++, p); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + // Clean up + if (reader != null) + reader.Dispose(); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + // Clean up + if (cmd != null) + cmd.Dispose(); + if (con != null) + con.Dispose(); + } + } +} + +/* Person UDT Class + An instance of a Person class represents an ODP_OBJ1_SAMPLE_PERSON_TYPE object + A custom type must implement INullable and IOracleCustomType interfaces +*/ +public class Person : INullable, IOracleCustomType +{ + private bool m_bIsNull; // Whether the Person object is NULL + private string m_name; // "NAME" attribute + private OracleString m_address; // "ADDRESS" attribute + private int? m_age; // "AGE" attribute + + // Implementation of INullable.IsNull + public virtual bool IsNull + { + get + { + return m_bIsNull; + } + } + + // Person.Null is used to return a NULL Person object + public static Person Null + { + get + { + Person p = new Person(); + p.m_bIsNull = true; + return p; + } + } + + // Specify the OracleObjectMappingAttribute to map "Name" to "NAME" + [OracleObjectMappingAttribute("NAME")] + // The mapping can also be specified using attribute index 0 + // [OracleObjectMappingAttribute(0)] + public string Name + { + get + { + return m_name; + } + set + { + m_name = value; + } + } + + // Specify the OracleObjectMappingAttribute to map "Address" to "ADDRESS" + [OracleObjectMappingAttribute("ADDRESS")] + // The mapping can also be specified using attribute index 1 + // [OracleObjectMappingAttribute(1)] + public OracleString Address + { + get + { + return m_address; + } + set + { + m_address = value; + } + } + + // Specify the OracleObjectMappingAttribute to map "Age" to "AGE" + [OracleObjectMappingAttribute("AGE")] + // The mapping can also be specified using attribute index 2 + // [OracleObjectMappingAttribute(2)] + + public int? Age + { + get + { + return m_age; + } + set + { + m_age = value; + } + } + + // Implementation of IOracleCustomType.FromCustomObject() + public virtual void FromCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Custom Type to Oracle Object + + // Set the "NAME" attribute. + // By default the "NAME" attribute will be set to NULL + if (m_name != null) + { + OracleUdt.SetValue(con, pUdt, "NAME", m_name); + // The "NAME" attribute can also be accessed by specifying index 0 + // OracleUdt.SetValue(con, pUdt, 0, m_name); + } + + // Set the "ADDRESS" attribute. + // By default the "ADDRESS" attribute will be set to NULL + if (!m_address.IsNull) + { + OracleUdt.SetValue(con, pUdt, "ADDRESS", m_address); + // The "ADDRESS" attribute can also be accessed by specifying index 1 + // OracleUdt.SetValue(con, pUdt, 1, m_address); + } + + // Set the "AGE" attribute. + + // By default the "AGE" attribute will be set to NULL + if (m_age != null) + { + OracleUdt.SetValue(con, pUdt, "AGE", m_age); + // The "AGE attribute can also be accessed by specifying index 2 + // OracleUdt.SetValue(con, pUdt, 2, m_age); + } + + } + + // Implementation of IOracleCustomType.ToCustomObject() + public virtual void ToCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Oracle Object to a Custom Type + + // Get the "NAME" attribute + // If the "NAME" attribute is NULL, then null will be returned + m_name = (string)OracleUdt.GetValue(con, pUdt, "NAME"); + + // The "NAME" attribute can also be accessed by specifying index 0 + // m_name = (string)OracleUdt.GetValue(con, pUdt, 0); + + // Get the "ADDRESS" attribute + // If the "ADDRESS" attribute is NULL, then OracleString.Null will be returned + m_address = (OracleString)OracleUdt.GetValue(con, pUdt, "ADDRESS"); + + // The "NAME" attribute can also be accessed by specifying index 1 + // m_address = (OracleString)OracleUdt.GetValue(con, pUdt, 1); + + // Get the "AGE" attribute + + // If the "AGE" attribute is NULL, then null will be returned + m_age = (int?)OracleUdt.GetValue(con, pUdt, "AGE"); + // The "AGE" attribute can also be accessed by specifying index 2 + // m_age = (int?)OracleUdt.GetValue(con, pUdt, 2); + + } + + public override string ToString() + { + // Return a string representation of the custom object + if (m_bIsNull) + return "Person.Null"; + else + { + string name = (m_name == null) ? "NULL" : m_name; + string address = (m_address.IsNull) ? "NULL" : m_address.Value; + string age = (m_age == null)? "NULL" : m_age.ToString(); + + return "Person(" + name + ", " + address + ", " + age + ")"; + } + } +} + +/* PersonFactory Class + An instance of the PersonFactory class is used to create Person objects +*/ +[OracleCustomTypeMappingAttribute("ODP_OBJ1_SAMPLE_PERSON_TYPE")] +public class PersonFactory : IOracleCustomTypeFactory +{ + // Implementation of IOracleCustomTypeFactory.CreateObject() + public IOracleCustomType CreateObject() + { + // Return a new custom object + return new Person(); + } +} + +/* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/udt/Ref-Inheritance.cs b/samples/udt/Ref-Inheritance.cs new file mode 100644 index 00000000..2ec6252a --- /dev/null +++ b/samples/udt/Ref-Inheritance.cs @@ -0,0 +1,540 @@ +/* +This sample demonstrates how to obtain Custom Type objects from + OracleRef objects. It also demonstrates how to update UDTs + through the OracleRef object and to obtain the appropriate + instance type for those UDTs that have an inheritance hierarchy + from OracleRef objects. This sample can use managed ODP.NET or + ODP.NET Core. + +Database schema setup scripts: + +1. Connect to HR or another similar schema. +2. Run the following SQL scripts to create a person type, + a student type that inherits from person type, and a table + that can store both person and student objects. One row of + each type will be added to the table. + +drop table odp_ref2_sample_person_obj_tab; +drop type odp_ref2_sample_student_type; +drop type odp_ref2_sample_person_type; + +create type odp_ref2_sample_person_type as object + (name varchar2(30), address varchar2(60), age number(3)) NOT FINAL; +/ +create type odp_ref2_sample_student_type under odp_ref2_sample_person_type + (dept_id number(2), major varchar2(20)); +/ + +-- odp_ref2_sample_person_obj_tab can store both persons and student objects +create table odp_ref2_sample_person_obj_tab of odp_ref2_sample_person_type; +insert into odp_ref2_sample_person_obj_tab values (odp_ref2_sample_person_type('John', 'Address 1', 20)); +insert into odp_ref2_sample_person_obj_tab values (odp_ref2_sample_student_type('Jim', 'Address 2', 25, NULL, 'Physics')); + +*/ + +using System; +using System.Data; +using Oracle.ManagedDataAccess.Client; +using Oracle.ManagedDataAccess.Types; + +class RefInheritanceSample +{ + static void Main(string[] args) + { + // Enter user id, password, and Oracle data source (i.e. net service name, EZ Connect, etc.) + string constr = "user id=;password=;data source="; + + string sqlInsertRef = "insert into odp_ref2_sample_person_obj_tab values (:1)"; + string sqlSelectRef = "select ref(p) from odp_ref2_sample_person_obj_tab p"; + string sqlSelectValue = "select value(p) from odp_ref2_sample_person_obj_tab p"; + string udtTypeNameP = "ODP_REF2_SAMPLE_PERSON_TYPE"; + string objTabNameP = "ODP_REF2_SAMPLE_PERSON_OBJ_TAB"; + + // Create a new Person object. + Person p = new Person(); + p.Name = "John"; + p.Address = "Address 1"; + p.Age = 20; + + // Create a new Student object. + Student s = new Student(); + s.Name = "Jim"; + s.Address = "Address 2"; + s.Age = 25; + s.Major = "Physics"; + + OracleConnection con = null; + OracleCommand cmd = new OracleCommand(); + OracleDataReader reader = null; + OracleTransaction txn = null; + OracleRef refP = null; // person REF + OracleRef refS = null; // student REF + + try + { + // Establish a connection to Oracle DB. + con = new OracleConnection(constr); + con.Open(); + cmd.Connection = con; + + try + { + // Inserting a person and a student instance into the odp_ref2_sample_person_obj_tab + txn = con.BeginTransaction(); + + cmd.CommandText = sqlInsertRef; + OracleParameter param = new OracleParameter("inParam", OracleDbType.Object, ParameterDirection.Input); + param.UdtTypeName = udtTypeNameP; + cmd.Parameters.Add(param); + + // Insert person + param.Value = p; + cmd.ExecuteNonQuery(); + + // Insert Student + param.Value = s; + cmd.ExecuteNonQuery(); + + txn.Commit(); + } + catch (Exception ex) + { + Console.WriteLine("Exception in inserting into {0}: {1}", objTabNameP, ex.Message); + } + finally + { + if (txn != null) + { + txn.Dispose(); + txn = null; + } + if (cmd != null) + cmd.Parameters.Clear(); + } + + try + { + // Retrieving REF from odp_ref2_sample_person_obj_tab + cmd.CommandText = sqlSelectRef; + + reader = cmd.ExecuteReader(); + int row = 1; + + while (reader.Read()) + { + if (row == 1) + refP = reader.GetOracleRef(0); + else + refS = reader.GetOracleRef(0); + row++; + } + + // Fetch rows from database table. + Person p1 = (Person)refP.GetCustomObject(); + Student s1 = (Student)refS.GetCustomObject(); + Console.WriteLine("Person: " + p1); + Console.WriteLine("Student: " + s1); + Console.WriteLine(); + } + catch (Exception ex) + { + Console.WriteLine("Exception in selecting from {0}: {1}", objTabNameP, ex.Message); + } + finally + { + if (reader != null) + { + reader.Dispose(); + reader = null; + } + } + + try + { + // Update person object. + txn = con.BeginTransaction(); + + Person p2 = (Person)refP.GetCustomObject(); + + // Update person's age using OracleRef. + p2.Age = p2.Age + 1; + refP.Update(p2); + + // p2 is updated to the database. + txn.Commit(); + } + catch (Exception ex) + { + Console.WriteLine("Exception in updating person in {0}: {1}", objTabNameP, ex.Message); + } + finally + { + if (txn != null) + { + txn.Dispose(); + txn = null; + } + } + + // Delete student object. + try + { + txn = con.BeginTransaction(); + refS.Delete(); + txn.Commit(); + } + catch (Exception ex) + { + Console.WriteLine("Exception in deleting student from {0}: {1}", objTabNameP, ex.Message); + } + finally + { + if (txn != null) + { + txn.Dispose(); + txn = null; + } + } + + try + { + // Retrieve rows from the database table. + cmd.CommandText = sqlSelectValue; + cmd.CommandType = CommandType.Text; + reader = cmd.ExecuteReader(); + + // Fetch each row. + int rowCount = 1; + while (reader.Read()) + { + // Fetch the objects as a custom type. + Person p3; + if (reader.IsDBNull(0)) + p3 = Person.Null; + else + p3 = (Person)reader.GetValue(0); + + Console.WriteLine("Row {0}: {1}", rowCount++, p3); + } + } + catch (Exception ex) + { + Console.WriteLine("Exception in selecting from {0}: {1}", objTabNameP, ex.Message); + } + finally + { + if (reader != null) + { + reader.Dispose(); + reader = null; + } + } + } + catch (Exception ex) + { + Console.WriteLine("Get exception: " + ex.Message); + } + finally + { + // Clean up + if (refS != null) + refS.Dispose(); + if (refP != null) + refP.Dispose(); + if (reader != null) + reader.Dispose(); + if (cmd != null) + cmd.Dispose(); + if (txn != null) + txn.Dispose(); + if (con != null) + { + con.Close(); + con.Dispose(); + } + } + } + + // Person Class + // A Person class instance represents an ODP_REF2_SAMPLE_PERSON_TYPE object. + // A custom type must implement INullable and IOracleCustomType interfaces. + public class Person : INullable, IOracleCustomType + { + private bool m_bIsNull; // Whether the Person object is NULL + private string m_name; // "NAME" attribute + private OracleString m_address; // "ADDRESS" attribute + private int? m_age; // "AGE" attribute + + // Implementation of INullable.IsNull + public virtual bool IsNull + { + get + { + return m_bIsNull; + } + } + + // Person.Null is used to return a NULL Person object. + public static Person Null + { + get + { + Person p = new Person(); + p.m_bIsNull = true; + return p; + } + } + + // Specify the OracleObjectMappingAttribute to map "Name" to "NAME". + [OracleObjectMappingAttribute("NAME")] + // The mapping can also be specified using attribute index 0. + // [OracleObjectMappingAttribute(0)] + public string Name + { + get + { + return m_name; + } + set + { + m_name = value; + } + } + + // Specify the OracleObjectMappingAttribute to map "Address" to "ADDRESS". + [OracleObjectMappingAttribute("ADDRESS")] + // The mapping can also be specified using attribute index 1. + // [OracleObjectMappingAttribute(1)] + public OracleString Address + { + get + { + return m_address; + } + set + { + m_address = value; + } + } + + // Specify the OracleObjectMappingAttribute to map "Age" to "AGE". + [OracleObjectMappingAttribute("AGE")] + // The mapping can also be specified using attribute index 2. + // [OracleObjectMappingAttribute(2)] + public int? Age + { + get + { + return m_age; + } + set + { + m_age = value; + } + } + + // Implementation of IOracleCustomType.FromCustomObject() + public virtual void FromCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Custom Type to Oracle Object + + // Set the "NAME" attribute. + // By default the "NAME" attribute will be set to NULL. + if (m_name != null) + { + OracleUdt.SetValue(con, pUdt, "NAME", m_name); + // The "NAME" attribute can also be accessed by specifying index 0. + // OracleUdt.SetValue(con, pUdt, 0, m_name); + } + + // Set the "ADDRESS" attribute. + // By default the "ADDRESS" attribute will be set to NULL. + if (!m_address.IsNull) + { + OracleUdt.SetValue(con, pUdt, "ADDRESS", m_address); + // The "ADDRESS" attribute can also be accessed by specifying index 1. + // OracleUdt.SetValue(con, pUdt, 1, m_address); + } + + // Set the "AGE" attribute. + // By default the "AGE" attribute will be set to NULL. + if (m_age != null) + { + OracleUdt.SetValue(con, pUdt, "AGE", m_age); + // The "AGE attribute can also be accessed by specifying index 2. + // OracleUdt.SetValue(con, pUdt, 2, m_age); + } + } + + // Implementation of IOracleCustomType.ToCustomObject() + public virtual void ToCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Oracle Object to a Custom Type. + + // Get the "NAME" attribute. + // If the "NAME" attribute is NULL, then null will be returned. + // The "NAME" attribute can also be accessed by specifying index 0. + m_name = (string)OracleUdt.GetValue(con, pUdt, "NAME"); + + // Get the "ADDRESS" attribute. + // If the "ADDRESS" attribute is NULL, then OracleString.Null will be returned. + // The "ADDRESS" attribute can also be accessed by specifying index 1. + m_address = (OracleString)OracleUdt.GetValue(con, pUdt, "ADDRESS"); + + // Get the "AGE" attribute. + // If the "AGE" attribute is NULL, then null will be returned. + // The "AGE" attribute can also be accessed by specifying index 2. + m_age = (int?)OracleUdt.GetValue(con, pUdt, "AGE"); + } + + public override string ToString() + { + // Return a string representation of the custom object + if (m_bIsNull) + return "Person.Null"; + else + { + string name = (m_name == null) ? "NULL" : m_name; + string address = (m_address.IsNull) ? "NULL" : m_address.Value; + string age = (m_age == null) ? "NULL" : m_age.ToString(); + return "Person(" + name + ", " + address + ", " + age + ")"; + } + } + } + + // PersonFactory Class + // An instance of the PersonFactory class is used to create Person objects. + [OracleCustomTypeMappingAttribute("ODP_REF2_SAMPLE_PERSON_TYPE")] + public class PersonFactory : IOracleCustomTypeFactory + { + // Implementation of IOracleCustomTypeFactory.CreateObject() + public IOracleCustomType CreateObject() + { + // Return a new custom object + return new Person(); + } + } + + // Student Class + // An instance of a Student class represents an ODP_REF2_SAMPLE_STUDENT_TYPE object + // Note: We do not map the "DEPT_ID" attribute (attribute index 3). So, it will always + // be NULL. A custom type must implement INullable and IOracleCustomType interfaces. + public class Student : Person, INullable, IOracleCustomType + { + private bool m_bIsNull; // Whether the Student object is NULL + private string m_major; // "MAJOR" attribute + + // Implementation of INullable.IsNull + public override bool IsNull + { + get + { + return m_bIsNull; + } + } + + // Student.Null is used to return a NULL Student object. + public new static Student Null + { + get + { + Student s = new Student(); + s.m_bIsNull = true; + return s; + } + } + + // Specify the OracleObjectMappingAttribute to map "Major" to "MAJOR". + [OracleObjectMappingAttribute("MAJOR")] + // The mapping can also be specified using attribute index 5. + // [OracleObjectMappingAttribute(5)] + public string Major + { + get + { + return m_major; + } + set + { + m_major = value; + } + } + + // Implementation of IOracleCustomType.FromCustomObject() + public override void FromCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Custom Type to Oracle Object. + // Invoke the base class conversion method. + base.FromCustomObject(con, pUdt); + + // Set the "MAJOR" attribute. + // By default the "MAJOR" attribute will be set to NULL. + // The "MAJOR" attribute can also be accessed by specifying index 5. + if (m_major != null) + OracleUdt.SetValue(con, pUdt, "MAJOR", m_major); + } + + // Implementation of IOracleCustomType.ToCustomObject() + public override void ToCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Oracle Object to a Custom Type. + // Invoke the base class conversion method. + base.ToCustomObject(con, pUdt); + + // Get the "MAJOR" attribute. + // If the "MAJOR" attribute is NULL, then "null" will be returned. + // The "MAJOR" attribute can also be accessed by specifying index 5. + m_major = (string)OracleUdt.GetValue(con, pUdt, "MAJOR"); + } + + public override string ToString() + { + // Return a string representation of the custom object. + if (m_bIsNull) + { + return "Student.Null"; + } + else + { + string name = (Name == null) ? "NULL" : Name; + string address = (Address.IsNull) ? "NULL" : Address.Value; + string age = (Age == null) ? "NULL" : Age.ToString(); + string major = (m_major == null) ? "NULL" : m_major; + return "Student(" + name + ", " + address + ", " + age + ", " + + major + ")"; + } + } + } + + // StudentFactory Class + // An instance of the StudentFactory class is used to create Student objects. + [OracleCustomTypeMappingAttribute("ODP_REF2_SAMPLE_STUDENT_TYPE")] + public class StudentFactory : IOracleCustomTypeFactory + { + // Implementation of IOracleCustomTypeFactory.CreateObject() + public IOracleCustomType CreateObject() + { + // Return a new custom object. + return new Student(); + } + } +} + +/* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/udt/Ref.cs b/samples/udt/Ref.cs new file mode 100644 index 00000000..ad1351ae --- /dev/null +++ b/samples/udt/Ref.cs @@ -0,0 +1,327 @@ +/* +This sample demonstrates how to fetch UDTs referenced by REFs. +This sample can use managed ODP.NET or ODP.NET Core. + +Database schema setup scripts: + +1. Connect to HR or another similar schema. +2. Run the following SQL scripts to create a Person type + and a table with with the Person type. Two rows will be + inserted into the table. Finally, a table using REFs to + the Person instances and a stored procedure that inserts + into that table will be created. + +drop procedure odp_ref1_sample_upd_contacts; +drop table odp_ref1_sample_contacts; +drop table odp_ref1_sample_person_obj_tab; +drop type odp_ref1_sample_person_type; + +create type odp_ref1_sample_person_type as object + (name varchar2(30), address varchar2(60), age number(3)) NOT FINAL; +/ + +create table odp_ref1_sample_person_obj_tab of odp_ref1_sample_person_type; + +insert into odp_ref1_sample_person_obj_tab values ( + 'John', 'Address 1', 20); +insert into odp_ref1_sample_person_obj_tab values ( + 'Jim', 'Address 2', 25); + +create table odp_ref1_sample_contacts ( + contact_ref ref odp_ref1_sample_person_type, + contact_phone varchar2(20)); + +create procedure odp_ref1_sample_upd_contacts( + param1 IN REF odp_ref1_sample_person_type, + param2 IN varchar2) as + begin + insert into odp_ref1_sample_contacts values(param1,param2); + end; +/ + +*/ + +using System; +using System.Data; +using Oracle.ManagedDataAccess.Client; +using Oracle.ManagedDataAccess.Types; + +class RefSample +{ + static void Main(string[] args) + { + // Enter user id, password, and Oracle data source (i.e. net service name, EZ Connect, etc.) + string constr = "user id=;password=;data source="; + + string sql1 = "select ref(p) from odp_ref1_sample_person_obj_tab p " + + "where p.name ='John'"; + string sql2 = "odp_ref1_sample_upd_contacts"; + string sql3 = "select deref(c.contact_ref), c.contact_phone " + + "from odp_ref1_sample_contacts c"; + + OracleConnection con = null; + OracleCommand cmd = null; + OracleDataReader reader1 = null; + OracleDataReader reader2 = null; + OracleRef refP = null; + + try + { + // Establish a connection to Oracle DB. + con = new OracleConnection(constr); + con.Open(); + + // Retrieve REF from the object table. + cmd = new OracleCommand(sql1, con); + cmd.CommandType = CommandType.Text; + reader1 = cmd.ExecuteReader(); + reader1.Read(); + refP = reader1.GetOracleRef(0); + Console.WriteLine("HEX value of ref object: {0}", refP.Value); + Console.WriteLine(); + + // Insert a row into the object-relational table with the + // REF PERSON value just retrieved (i.e. John) + cmd.CommandText = sql2; + cmd.CommandType = CommandType.StoredProcedure; + OracleParameter param1 = new OracleParameter(); + + param1.OracleDbType = OracleDbType.Ref; + param1.Direction = ParameterDirection.Input; + + // Note: The UdtTypeName is case-senstive. + param1.UdtTypeName = "ODP_REF1_SAMPLE_PERSON_TYPE"; + param1.Value = refP; + + cmd.Parameters.Add(param1); + + OracleParameter param2 = new OracleParameter(); + param2.OracleDbType = OracleDbType.Varchar2; + param2.Direction = ParameterDirection.Input; + param2.Value = "1-800-555-4412"; + + cmd.Parameters.Add(param2); + cmd.ExecuteNonQuery(); + + // Retrieve the rows containing the name, John. + cmd.Parameters.Clear(); + cmd.CommandText = sql3; + cmd.CommandType = CommandType.Text; + reader2 = cmd.ExecuteReader(); + + // Fetch each row + int rowCount = 1; + while (reader2.Read()) + { + // Fetch the object as a custom type + Person p; + if (reader2.IsDBNull(0)) + p = Person.Null; + else + p = (Person)reader2.GetValue(0); + string phone = reader2.GetString(1); + Console.WriteLine("Row {0}: {1}, {2}", rowCount++, p, phone); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + // Clean up + if (reader1 != null) + reader1.Dispose(); + if (reader2 != null) + reader2.Dispose(); + if (refP != null) + refP.Dispose(); + if (cmd != null) + cmd.Dispose(); + if (con != null) + con.Dispose(); + } + } +} + +// Person Class +// An instance of a Person class represents an ODP_REF1_SAMPLE_PERSON_TYPE object. +// A custom type must implement INullable and IOracleCustomType interfaces. +public class Person : INullable, IOracleCustomType +{ + private bool m_bIsNull; // Whether the Person object is NULL + private string m_name; // "NAME" attribute + private OracleString m_address; // "ADDRESS" attribute + private int? m_age; // "AGE" attribute + + // Implementation of INullable.IsNull + public virtual bool IsNull + { + get + { + return m_bIsNull; + } + } + + // Person.Null is used to return a NULL Person object. + public static Person Null + { + get + { + Person p = new Person(); + p.m_bIsNull = true; + return p; + } + } + + // Specify the OracleObjectMappingAttribute to map "Name" to "NAME". + [OracleObjectMappingAttribute("NAME")] + // The mapping can also be specified using attribute index 0. + // [OracleObjectMappingAttribute(0)] + public string Name + { + get + { + return m_name; + } + set + { + m_name = value; + } + } + + // Specify the OracleObjectMappingAttribute to map "Address" to "ADDRESS". + [OracleObjectMappingAttribute("ADDRESS")] + // The mapping can also be specified using attribute index 1. + // [OracleObjectMappingAttribute(1)] + public OracleString Address + { + get + { + return m_address; + } + set + { + m_address = value; + } + } + + // Specify the OracleObjectMappingAttribute to map "Age" to "AGE". + [OracleObjectMappingAttribute("AGE")] + // The mapping can also be specified using attribute index 2. + // [OracleObjectMappingAttribute(2)] + public int? Age + { + get + { + return m_age; + } + set + { + m_age = value; + } + } + + // Implementation of IOracleCustomType.FromCustomObject() + public virtual void FromCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Custom Type to Oracle Object. + + // Set the "NAME" attribute. + // By default the "NAME" attribute will be set to NULL. + if (m_name != null) + { + OracleUdt.SetValue(con, pUdt, "NAME", m_name); + // The "NAME" attribute can also be accessed by specifying index 0. + // OracleUdt.SetValue(con, pUdt, 0, m_name); + } + + // Set the "ADDRESS" attribute. + // By default the "ADDRESS" attribute will be set to NULL. + if (!m_address.IsNull) + { + OracleUdt.SetValue(con, pUdt, "ADDRESS", m_address); + // The "ADDRESS" attribute can also be accessed by specifying index 1. + // OracleUdt.SetValue(con, pUdt, 1, m_address); + } + + // Set the "AGE" attribute. + // By default the "AGE" attribute will be set to NULL. + if (m_age != null) + { + OracleUdt.SetValue(con, pUdt, "AGE", m_age); + // The "AGE attribute can also be accessed by specifying index 2. + // OracleUdt.SetValue(con, pUdt, 2, m_age); + } + } + + // Implementation of IOracleCustomType.ToCustomObject() + public virtual void ToCustomObject(OracleConnection con, object pUdt) + { + // Convert from the Oracle Object to a Custom Type. + + // Get the "NAME" attribute. + // If the "NAME" attribute is NULL, then null will be returned. + m_name = (string)OracleUdt.GetValue(con, pUdt, "NAME"); + // The "NAME" attribute can also be accessed by specifying index 0. + // m_name = (string)OracleUdt.GetValue(con, pUdt, 0); + + // Get the "ADDRESS" attribute. + // If the "ADDRESS" attribute is NULL, then OracleString.Null will be returned. + m_address = (OracleString)OracleUdt.GetValue(con, pUdt, "ADDRESS"); + // The "ADDRESS" attribute can also be accessed by specifying index 1. + // m_address = (OracleString)OracleUdt.GetValue(con, pUdt, 1); + + // Get the "AGE" attribute. + // If the "AGE" attribute is NULL, then null will be returned. + m_age = (int?)OracleUdt.GetValue(con, pUdt, "AGE"); + // The "AGE" attribute can also be accessed by specifying index 2. + // m_age = (int?)OracleUdt.GetValue(con, pUdt, 2); + } + + public override string ToString() + { + // Return a string representation of the custom object. + if (m_bIsNull) + return "Person.Null"; + else + { + string name = (m_name == null) ? "NULL" : m_name; + string address = (m_address.IsNull) ? "NULL" : m_address.Value; + string age = (m_age == null)? "NULL" : m_age.ToString(); + return "Person(" + name + ", " + address + ", " + age + ")"; + } + } +} + +// PersonFactory Class +// An instance of the PersonFactory class is used to create Person objects. +[OracleCustomTypeMappingAttribute("ODP_REF1_SAMPLE_PERSON_TYPE")] +public class PersonFactory : IOracleCustomTypeFactory +{ + // Implementation of IOracleCustomTypeFactory.CreateObject() + public IOracleCustomType CreateObject() + { + // Return a new custom object. + return new Person(); + } +} + +/* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/udt/Spatial-UDT.cs b/samples/udt/Spatial-UDT.cs new file mode 100644 index 00000000..8dec766c --- /dev/null +++ b/samples/udt/Spatial-UDT.cs @@ -0,0 +1,343 @@ +/* +This sample demonstrates how to map and fetch types + similar to Oracle Spatial types as custom types. This + sample can use managed ODP.NET or ODP.NET Core. + +Database schema setup scripts: + +1. Connect to HR or another similar schema. +2. Run the following SQL scripts to create Spatial + types, a table with using these types, and insert + a row of sample data. + +drop table odp_sample_sdo_geo_obj_tab; +drop type odp_sample_sdo_geometry_type; +drop type odp_sample_sdo_ordinate_type; +drop type odp_sample_sdo_elem_info_type; +drop type odp_sample_sdo_point_type; + +create type odp_sample_sdo_point_type as object + (sdo_point_x number, sdo_point_y number, sdo_point_z number); +/ + +create type odp_sample_sdo_elem_info_type as varray(100) of number; +/ + +create type odp_sample_sdo_ordinate_type as varray(100) of number; +/ + +create type odp_sample_sdo_geometry_type as object + (sdo_gtype number, sdo_srid number, sdo_point odp_sample_sdo_point_type, + sdo_elem_info odp_sample_sdo_elem_info_type, + sdo_ordinate odp_sample_sdo_ordinate_type); +/ + +create table odp_sample_sdo_geo_obj_tab of odp_sample_sdo_geometry_type; + +insert into odp_sample_sdo_geo_obj_tab values(odp_sample_sdo_geometry_type( + 123,123,odp_sample_sdo_point_type(123.45,123.45,123.45), + odp_sample_sdo_elem_info_type(123,123), + odp_sample_sdo_ordinate_type(123.45,123.45))); + +commit; + +*/ + +using System; +using Oracle.ManagedDataAccess.Client; +using Oracle.ManagedDataAccess.Types; + +class SpatialTypeSample +{ + static void Main(string[] args) + { + // Enter user id, password, and Oracle data source (i.e. net service name, EZ Connect, etc.) + string constr = "user id=;password=;data source="; + + string sql1 = "select value(p) from odp_sample_sdo_geo_obj_tab p"; + + OracleConnection con = null; + OracleCommand cmd = null; + OracleDataReader reader = null; + + try + { + // Establish a connection to Oracle database + con = new OracleConnection(constr); + con.Open(); + + cmd = new OracleCommand(sql1, con); + reader = cmd.ExecuteReader(); + + // Fetch each row + int rowCount = 1; + while (reader.Read()) + { + // Fetch the objects as a custom type + SdoGeometry p; + if (reader.IsDBNull(0)) + p = SdoGeometry.Null; + else + p = (SdoGeometry)reader.GetValue(0); + + Console.WriteLine("Row {0}: {1}", rowCount++, p); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + // Clean up + if (reader != null) + reader.Dispose(); + if (cmd != null) + cmd.Dispose(); + if (con != null) + con.Dispose(); + } + } +} + +// Oracle Spatial Classes + +// The SdoPoint class has the attributes X, Y, and Z, all of type double. +public class SdoPoint : IOracleCustomType, INullable +{ + [OracleObjectMapping(0)] + public double X; + [OracleObjectMapping(1)] + public double Y; + [OracleObjectMapping(2)] + public double Z; + + private bool m_bIsNull; + + public bool IsNull + { + get + { + return m_bIsNull; + } + } + + public static SdoPoint Null + { + get + { + SdoPoint obj = new SdoPoint(); + obj.m_bIsNull = true; + return obj; + } + } + + public override string ToString() + { + if (m_bIsNull) + return "SdoPoint.Null"; + else + return "SdoPoint(" + X + "," + Y + "," + Z + ")"; + } + + public void ToCustomObject(OracleConnection con, object pUdt) + { + // If the UDT may contain NULL attribute data, enable the following code + //if (!OracleUdt.IsDBNull(con, pUdt, 0)) + X = (double)OracleUdt.GetValue(con, pUdt, 0); + + // If the UDT may contain NULL attribute data, enable the following code + //if (!OracleUdt.IsDBNull(con, pUdt, 1)) + Y = (double)OracleUdt.GetValue(con, pUdt, 1); + + // If the UDT may contain NULL attribute data, enable the following code + //if (!OracleUdt.IsDBNull(con, pUdt, 2)) + Z = (double)OracleUdt.GetValue(con, pUdt, 2); + } + + public void FromCustomObject(OracleConnection con, object pUdt) + { + OracleUdt.SetValue(con, pUdt, 0, X); + OracleUdt.SetValue(con, pUdt, 1, Y); + OracleUdt.SetValue(con, pUdt, 2, Z); + } +} + +// An instance of the SdoPointFactory class is used to create SdoPoint objects. +[OracleCustomTypeMapping("ODP_SAMPLE_SDO_POINT_TYPE")] +public class SdoPointFactory : IOracleCustomTypeFactory +{ + // IOracleCustomTypeFactory Inteface + public IOracleCustomType CreateObject() + { + SdoPoint sdoPoint = new SdoPoint(); + return sdoPoint; + } +} + +// The SdoGeometry class is a spatial object's geometric description stored in a single row, +// in a single column of object type ODP_SAMPLE_SDO_GEOMETRY_TYPE in an user-defined table. +// The object is similar to the standard Oracle Spatial SDO_GEOMETRY object type. +public class SdoGeometry : INullable, IOracleCustomType +{ + [OracleObjectMapping(0)] + public int _gtype; + [OracleObjectMapping(1)] + public int _srid; + [OracleObjectMapping(2)] + public SdoPoint _point; + [OracleObjectMapping(3)] + public int[] _elementInfo; + [OracleObjectMapping(4)] + public double[] _ordinates; + + private bool m_bIsNull; + + public bool IsNull + { + get + { + return m_bIsNull; + } + } + + public static SdoGeometry Null + { + get + { + SdoGeometry obj = new SdoGeometry(); + obj.m_bIsNull = true; + return obj; + } + } + + public void ToCustomObject(OracleConnection con, object pUdt) + { + // If the UDT may contain NULL attribute data, enable the following code + //if (!OracleUdt.IsDBNull(con, pUdt, 0)) + _gtype = (int)OracleUdt.GetValue(con, pUdt, 0); + + // If the UDT may contain NULL attribute data, enable the following code + //if (!OracleUdt.IsDBNull(con, pUdt, 0)) + _srid = (int)OracleUdt.GetValue(con, pUdt, 1); + _point = (SdoPoint)OracleUdt.GetValue(con, pUdt, 2); + _elementInfo = (int[])OracleUdt.GetValue(con, pUdt, 3); + _ordinates = (double[])OracleUdt.GetValue(con, pUdt, 4); + } + + public void FromCustomObject(OracleConnection con, object pUdt) + { + OracleUdt.SetValue(con, pUdt, 0, _gtype); + OracleUdt.SetValue(con, pUdt, 1, _srid); + OracleUdt.SetValue(con, pUdt, 2, _point); + OracleUdt.SetValue(con, pUdt, 3, _elementInfo); + OracleUdt.SetValue(con, pUdt, 4, _ordinates); + } + + public int[] ElementInfo + { + get + { + return _elementInfo; + } + } + + public double[] Ordinates + { + get + { + return _ordinates; + } + } + + public override string ToString() + { + string eleminfostr = String.Empty, ordinatesstr = String.Empty; + if (m_bIsNull) + return "SdoGeometry.Null"; + else + { + eleminfostr = _elementInfo[0].ToString(); + for (int i = 1; i < _elementInfo.Length; i++) + eleminfostr += "," + _elementInfo[i]; + eleminfostr = "ElementInfo(" + eleminfostr + ")"; + + ordinatesstr = _ordinates[0].ToString(); + for (int i = 1; i < _ordinates.Length; i++) + ordinatesstr += "," + _ordinates[i]; + ordinatesstr = "Ordinates(" + ordinatesstr + ")"; + } + return String.Format("SdoGeometry({0},{1},{2},{3},{4})", + _gtype, _srid, _point, eleminfostr, ordinatesstr); + } +} + +// An instance of the SdoGeometryFactory class is used to create SdoGeometry objects. +[OracleCustomTypeMapping("ODP_SAMPLE_SDO_GEOMETRY_TYPE")] +public class SdoGeometryFactory : IOracleCustomTypeFactory +{ + // IOracleCustomTypeFactory Inteface + public IOracleCustomType CreateObject() + { + return new SdoGeometry(); + } +} + +// An instance of the SdoElemInfoArrayFactory class is used to create an +// SDO element information array. +[OracleCustomTypeMapping("ODP_SAMPLE_SDO_ELEM_INFO_TYPE")] +public class SdoElemInfoArrayFactory : IOracleArrayTypeFactory +{ + // IOracleArrayTypeFactory.CreateArray Inteface + public Array CreateArray(int numElems) + { + return new int[numElems]; + } + + // IOracleArrayTypeFactory.CreateStatusArray + public Array CreateStatusArray(int numElems) + { + // An OracleUdtStatus[] is not required to store null status information + // if there is no NULL attribute data in the element array + return null; + } +} + +// An instance of the SdoOrdinateArrayFactory class is used to create an SDO +// ordinate array, which indicates the spatial object coordinate boundaries. +[OracleCustomTypeMapping("ODP_SAMPLE_SDO_ORDINATE_TYPE")] +public class SdoOrdinateArrayFactory : IOracleArrayTypeFactory +{ + // IOracleArrayTypeFactory.CreateArray Inteface + public Array CreateArray(int numElems) + { + return new double[numElems]; + } + + // IOracleArrayTypeFactory.CreateStatusArray + public Array CreateStatusArray(int numElems) + { + // An OracleUdtStatus[] is not required to store null status information + // if there is no NULL attribute data in the element array + return null; + } +} + +/* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/samples/udt/VArray.cs b/samples/udt/VArray.cs new file mode 100644 index 00000000..7f25def9 --- /dev/null +++ b/samples/udt/VArray.cs @@ -0,0 +1,303 @@ +/* +This sample demonstrates how to map, fetch, and + manipulate the Oracle VARRAY as a custom object. + This sample can use managed ODP.NET or ODP.NET Core. + +Database schema setup scripts: + +1. Connect to HR or another similar schema. +2. Run the following SQL scripts to create a varray of + numbers, a table of that varray, and a stored + procedure inserts a new varray into that table. + +drop procedure odp_varray_sample_proc; +drop table odp_varray_sample_rel_tab; +drop type odp_varray_sample_type; + +create type odp_varray_sample_type as varray(10) of number; +/ + +create table odp_varray_sample_rel_tab + (col1 odp_varray_sample_type); + +create procedure odp_varray_sample_proc( + param1 IN OUT odp_varray_sample_type) as + begin + param1.Extend(1); + param1(param1.Last) := 9; + insert into odp_varray_sample_rel_tab values(param1); + end; +/ + +*/ + +using System; +using System.Data; +using System.Collections; +using Oracle.ManagedDataAccess.Client; +using Oracle.ManagedDataAccess.Types; + +class VArraySample +{ + static void Main(string[] args) + { + // Enter user id, password, and Oracle data source (i.e. net service name, EZ Connect, etc.) + string constr = "user id=;password=;data source="; + + string sql1 = "select col1 from odp_varray_sample_rel_tab"; + string sql2 = "odp_varray_sample_proc"; + + // Create a new simple varray with values 1, 2, 3, and 4. + SimpleVarray pa = new SimpleVarray(); + pa.Array = new Int32[] { 1, 2, 3, 4 }; + + // Create status array and indicate element 2 is Null. + pa.StatusArray = new OracleUdtStatus[] { OracleUdtStatus.NotNull, + OracleUdtStatus.Null, OracleUdtStatus.NotNull, OracleUdtStatus.NotNull }; + + OracleConnection con = null; + OracleCommand cmd = null; + OracleDataReader reader = null; + + try + { + // Establish a connection to Oracle DB. + con = new OracleConnection(constr); + con.Open(); + + cmd = new OracleCommand(sql2, con); + cmd.CommandType = CommandType.StoredProcedure; + + OracleParameter param = new OracleParameter(); + param.OracleDbType = OracleDbType.Array; + param.Direction = ParameterDirection.InputOutput; + + // Note: The UdtTypeName is case-senstive. + param.UdtTypeName = "ODP_VARRAY_SAMPLE_TYPE"; + param.Value = pa; + cmd.Parameters.Add(param); + + // Insert SimpleVarray(1, NULL, 3, 4) into the table. + // The stored procedure adds a fifth VARRAY element with a value + // of 9, then inserts the VARRAY into the table. + cmd.ExecuteNonQuery(); + + // Print out the updated Simple Varray. + // Results should return values: 1, NULL, 3, 4, and 9. + Console.WriteLine("Updated SimpleVarray: " + param.Value); + Console.WriteLine(); + + // Modify element 3 to Null and element 2 to Not Null. + pa.StatusArray[1] = OracleUdtStatus.NotNull; + pa.StatusArray[2] = OracleUdtStatus.Null; + + param.Value = pa; + + // Insert SimpleVarray(1, 2, NULL, 4) into the table. + // The stored procedure adds a fifth VARRAY element with a value + // of 9, then inserts the VARRAY into the table. + cmd.ExecuteNonQuery(); + + // Print out the updated Simple Varray. + // Results should return values: 1, 2, NULL, 4, and 9. + Console.WriteLine("Updated SimpleVarray: " + param.Value); + Console.WriteLine(); + + // Add/Remove some elements by converting the Int32[] to an ArrayList. + ArrayList pa1 = new ArrayList(pa.Array); + + // Create a corresponding array list to track each element's + // Null or NotNull status. + ArrayList sa1 = new ArrayList(pa.StatusArray); + + // Remove the first element. (2, 3, 4) + pa1.RemoveAt(0); + sa1.RemoveAt(0); + + // Add element 6. (2, 3, 4, 6) + pa1.Add(6); + sa1.Add(OracleUdtStatus.NotNull); + + // Add element -1. (2, 3, 4, 6, -1) + pa1.Add(-1); + // Make the new element NULL now when inserted into DB. + sa1.Add(OracleUdtStatus.Null); + + // Convert ArrayLists into a SimpleVarray + pa.Array = (Int32[])pa1.ToArray(typeof(Int32)); + pa.StatusArray = (OracleUdtStatus[])sa1.ToArray(typeof(OracleUdtStatus)); + + param.Value = pa; + + Console.WriteLine("Updated SimpleVarray: " + param.Value); + Console.WriteLine(); + + // Insert SimpleVarray(2, NULL, 4, 6, NULL) into the table. + // The stored procedure adds a sixth VARRAY element with a value + // of 9, then inserts the VARRAY into the table. + cmd.ExecuteNonQuery(); + + cmd.CommandText = sql1; + cmd.CommandType = CommandType.Text; + reader = cmd.ExecuteReader(); + + // Fetch each row and display the VARRAY data. + // Results should return values 2, NULL, 4, 6, NULL, and 9 + // for the last SimpleArray returned. + int rowCount = 1; + while (reader.Read()) + { + // Fetch the objects as custom types. + SimpleVarray p; + if (reader.IsDBNull(0)) + p = SimpleVarray.Null; + else + p = (SimpleVarray)reader.GetValue(0); + + Console.WriteLine("Row {0}: {1}", rowCount++, p); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + // Clean up + if (reader != null) + reader.Dispose(); + if (cmd != null) + cmd.Dispose(); + if (con != null) + con.Dispose(); + } + } +} + +// SimpleVarray Class +// A SimpleVarray class instance represents an ODP_VARRAY_SAMPLE_TYPE object. +// A custom type must implement INullable and IOracleCustomType interfaces. +public class SimpleVarray : IOracleCustomType, INullable +{ + [OracleArrayMapping()] + public Int32[] Array; + private OracleUdtStatus[] m_statusArray; + + // OracleUdtStatus enumeration values specify the object attribute + // or collection element status. + public OracleUdtStatus[] StatusArray + { + get + { + return this.m_statusArray; + } + set + { + this.m_statusArray = value; + } + } + + private bool m_bIsNull; + + // Implementation of INullable.IsNull + public bool IsNull + { + get + { + return m_bIsNull; + } + } + + // SimpleVarray.Null is used to return a NULL SimpleVarray object. + public static SimpleVarray Null + { + get + { + SimpleVarray obj = new SimpleVarray(); + obj.m_bIsNull = true; + return obj; + } + } + + // Implementation of IOracleCustomType.ToCustomObject() + public void ToCustomObject(OracleConnection con, object pUdt) + { + object objectStatusArray = null; + Array = (Int32[])OracleUdt.GetValue(con, pUdt, 0, out objectStatusArray); + m_statusArray = (OracleUdtStatus[])objectStatusArray; + } + + // Implementation of IOracleCustomType.FromCustomObject() + public void FromCustomObject(OracleConnection con, object pUdt) + { + OracleUdt.SetValue(con, pUdt, 0, Array, m_statusArray); + } + + public override string ToString() + { + // Return a string representation of the custom object. + if (m_bIsNull) + return "SimpleVarray.Null"; + else + { + string rtnstr = String.Empty; + if (m_statusArray[0] == OracleUdtStatus.Null) + rtnstr = "NULL"; + else + rtnstr = Array.GetValue(0).ToString(); + for (int i = 1; i < m_statusArray.Length; i++) + { + if (m_statusArray[i] == OracleUdtStatus.Null) + rtnstr += "," + "NULL"; + else + rtnstr += "," + Array.GetValue(i).ToString(); + } + return "SimpleVarray(" + rtnstr + ")"; + } + } +} + +// SimpleVarrayFactory Class +// An instance of the SimpleVarrayFactory class is used to create +// SimpleVarray objects. +[OracleCustomTypeMapping("ODP_VARRAY_SAMPLE_TYPE")] +public class SimpleVarrayFactory : IOracleCustomTypeFactory, IOracleArrayTypeFactory +{ + // IOracleCustomTypeFactory + public IOracleCustomType CreateObject() + { + return new SimpleVarray(); + } + + // IOracleArrayTypeFactory Inteface + public Array CreateArray(int numElems) + { + return new Int32[numElems]; + } + + public Array CreateStatusArray(int numElems) + { + // CreateStatusArray may return null if null status information + // is not required. + return new OracleUdtStatus[numElems]; + } +} + +/* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/schemas/scott.sql b/schemas/scott.sql index f843ba32..bed223a7 100644 --- a/schemas/scott.sql +++ b/schemas/scott.sql @@ -1,33 +1,14 @@ -Rem Copyright (c) 2016 by Oracle Corporation -Rem -Rem You may not use the identified files except in compliance with The MIT -Rem License (the "License.") -Rem -Rem You may obtain a copy of the License at -Rem https://github.com/oracle/Oracle.NET/blob/master/LICENSE -Rem -Rem Unless required by applicable law or agreed to in writing, software -Rem distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -Rem WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -Rem -Rem See the License for the specific language governing permissions and -Rem limitations under the License. -Rem Rem NAME -REM scott.sql +Rem scott.sql Rem Rem DESCRIPTION Rem SCOTT is a database user whose schema is used for Oracle code demonstrations -Rem Be sure to replace on lines 31 and 34 with your preferred password. +Rem Be sure to replace on lines 12 and 15 with your preferred password. Rem Historically, "tiger" has been SCOTT schema's password. - SET TERMOUT OFF SET ECHO OFF -rem CONGDON Invoked in RDBMS at build time. 29-DEC-1988 -rem OATES: Created: 16-Feb-83 - GRANT CONNECT,RESOURCE,UNLIMITED TABLESPACE TO SCOTT IDENTIFIED BY ; ALTER USER SCOTT DEFAULT TABLESPACE USERS; ALTER USER SCOTT TEMPORARY TABLESPACE TEMP; @@ -69,13 +50,13 @@ INSERT INTO EMP VALUES INSERT INTO EMP VALUES (7782,'CLARK','MANAGER',7839,to_date('9-6-1981','dd-mm-yyyy'),2450,NULL,10); INSERT INTO EMP VALUES -(7788,'SCOTT','ANALYST',7566,to_date('13-JUL-87')-85,3000,NULL,20); +(7788,'SCOTT','ANALYST',7566,to_date('13-07-87','dd-mm-rr')-85,3000,NULL,20); INSERT INTO EMP VALUES (7839,'KING','PRESIDENT',NULL,to_date('17-11-1981','dd-mm-yyyy'),5000,NULL,10); INSERT INTO EMP VALUES (7844,'TURNER','SALESMAN',7698,to_date('8-9-1981','dd-mm-yyyy'),1500,0,30); INSERT INTO EMP VALUES -(7876,'ADAMS','CLERK',7788,to_date('13-JUL-87')-51,1100,NULL,20); +(7876,'ADAMS','CLERK',7788,to_date('13-07-87','dd-mm-rr')-51,1100,NULL,20); INSERT INTO EMP VALUES (7900,'JAMES','CLERK',7698,to_date('3-12-1981','dd-mm-yyyy'),950,NULL,30); INSERT INTO EMP VALUES @@ -104,3 +85,18 @@ COMMIT; SET TERMOUT ON SET ECHO ON + +Rem Copyright (c) 2016, 2024 by Oracle Corporation +Rem +Rem You may not use the identified files except in compliance with The MIT +Rem License (the "License.") +Rem +Rem You may obtain a copy of the License at +Rem https://github.com/oracle/dotnet-db-samples/blob/master/LICENSE.txt +Rem +Rem Unless required by applicable law or agreed to in writing, software +Rem distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Rem WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +Rem +Rem See the License for the specific language governing permissions and +Rem limitations under the License. diff --git a/session-demos/2019/odtscreenshots/codegen.png b/session-demos/2019/odtscreenshots/codegen.png new file mode 100644 index 00000000..213de07b Binary files /dev/null and b/session-demos/2019/odtscreenshots/codegen.png differ diff --git a/session-demos/2019/odtscreenshots/hover.png b/session-demos/2019/odtscreenshots/hover.png new file mode 100644 index 00000000..5068731d Binary files /dev/null and b/session-demos/2019/odtscreenshots/hover.png differ diff --git a/session-demos/2019/odtscreenshots/intellisense.png b/session-demos/2019/odtscreenshots/intellisense.png new file mode 100644 index 00000000..2781058f Binary files /dev/null and b/session-demos/2019/odtscreenshots/intellisense.png differ diff --git a/session-demos/2019/odtscreenshots/intellisenseproc1.png b/session-demos/2019/odtscreenshots/intellisenseproc1.png new file mode 100644 index 00000000..41423108 Binary files /dev/null and b/session-demos/2019/odtscreenshots/intellisenseproc1.png differ diff --git a/session-demos/2019/odtscreenshots/intellisenseproc2.png b/session-demos/2019/odtscreenshots/intellisenseproc2.png new file mode 100644 index 00000000..0857cdc3 Binary files /dev/null and b/session-demos/2019/odtscreenshots/intellisenseproc2.png differ diff --git a/session-demos/2019/odtscreenshots/odtcloudexplorer2170.jpg b/session-demos/2019/odtscreenshots/odtcloudexplorer2170.jpg new file mode 100644 index 00000000..8b8ade1c Binary files /dev/null and b/session-demos/2019/odtscreenshots/odtcloudexplorer2170.jpg differ diff --git a/session-demos/2019/odtscreenshots/odtgalleryperftune.png b/session-demos/2019/odtscreenshots/odtgalleryperftune.png new file mode 100644 index 00000000..06531f44 Binary files /dev/null and b/session-demos/2019/odtscreenshots/odtgalleryperftune.png differ diff --git a/session-demos/2019/odtscreenshots/schemacompresultswindow.png b/session-demos/2019/odtscreenshots/schemacompresultswindow.png new file mode 100644 index 00000000..8da2327d Binary files /dev/null and b/session-demos/2019/odtscreenshots/schemacompresultswindow.png differ diff --git a/session-demos/2019/odtscreenshots/sqlmonitor.png b/session-demos/2019/odtscreenshots/sqlmonitor.png new file mode 100644 index 00000000..8d503d6b Binary files /dev/null and b/session-demos/2019/odtscreenshots/sqlmonitor.png differ diff --git a/session-demos/2019/odtscreenshots/sqlmonitorreport.png b/session-demos/2019/odtscreenshots/sqlmonitorreport.png new file mode 100644 index 00000000..7889c5c6 Binary files /dev/null and b/session-demos/2019/odtscreenshots/sqlmonitorreport.png differ diff --git a/session-demos/2019/odtscreenshots/tabledesigner.png b/session-demos/2019/odtscreenshots/tabledesigner.png new file mode 100644 index 00000000..c5dd0ed3 Binary files /dev/null and b/session-demos/2019/odtscreenshots/tabledesigner.png differ diff --git a/session-demos/2019/odtvscodescreenshots/autocomplete1_2160.png b/session-demos/2019/odtvscodescreenshots/autocomplete1_2160.png new file mode 100644 index 00000000..87bf4e50 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/autocomplete1_2160.png differ diff --git a/session-demos/2019/odtvscodescreenshots/autocompletealias.gif b/session-demos/2019/odtvscodescreenshots/autocompletealias.gif new file mode 100644 index 00000000..f191b280 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/autocompletealias.gif differ diff --git a/session-demos/2019/odtvscodescreenshots/autocompletealias.png b/session-demos/2019/odtvscodescreenshots/autocompletealias.png new file mode 100644 index 00000000..09bd8990 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/autocompletealias.png differ diff --git a/session-demos/2019/odtvscodescreenshots/bookmarks.png b/session-demos/2019/odtvscodescreenshots/bookmarks.png index dd4799bf..6aa17a58 100644 Binary files a/session-demos/2019/odtvscodescreenshots/bookmarks.png and b/session-demos/2019/odtvscodescreenshots/bookmarks.png differ diff --git a/session-demos/2019/odtvscodescreenshots/codegen.png b/session-demos/2019/odtvscodescreenshots/codegen.png new file mode 100644 index 00000000..f094b4cb Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/codegen.png differ diff --git a/session-demos/2019/odtvscodescreenshots/condialogez2150.png b/session-demos/2019/odtvscodescreenshots/condialogez2150.png new file mode 100644 index 00000000..edaf1d66 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/condialogez2150.png differ diff --git a/session-demos/2019/odtvscodescreenshots/condialogez2160.png b/session-demos/2019/odtvscodescreenshots/condialogez2160.png new file mode 100644 index 00000000..64153d77 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/condialogez2160.png differ diff --git a/session-demos/2019/odtvscodescreenshots/condialogez2180.png b/session-demos/2019/odtvscodescreenshots/condialogez2180.png new file mode 100644 index 00000000..6ad02219 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/condialogez2180.png differ diff --git a/session-demos/2019/odtvscodescreenshots/datagrid2130.png b/session-demos/2019/odtvscodescreenshots/datagrid2130.png new file mode 100644 index 00000000..0644f5fa Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/datagrid2130.png differ diff --git a/session-demos/2019/odtvscodescreenshots/datagrid2430.png b/session-demos/2019/odtvscodescreenshots/datagrid2430.png new file mode 100644 index 00000000..6eb78120 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/datagrid2430.png differ diff --git a/session-demos/2019/odtvscodescreenshots/debugging.gif b/session-demos/2019/odtvscodescreenshots/debugging.gif new file mode 100644 index 00000000..f191b280 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/debugging.gif differ diff --git a/session-demos/2019/odtvscodescreenshots/debugging.png b/session-demos/2019/odtvscodescreenshots/debugging.png new file mode 100644 index 00000000..0b9adeaf Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/debugging.png differ diff --git a/session-demos/2019/odtvscodescreenshots/explainplangrid.png b/session-demos/2019/odtvscodescreenshots/explainplangrid.png new file mode 100644 index 00000000..741869ac Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/explainplangrid.png differ diff --git a/session-demos/2019/odtvscodescreenshots/explainplangtext.png b/session-demos/2019/odtvscodescreenshots/explainplangtext.png new file mode 100644 index 00000000..0309f933 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/explainplangtext.png differ diff --git a/session-demos/2019/odtvscodescreenshots/explorer2140.png b/session-demos/2019/odtvscodescreenshots/explorer2140.png new file mode 100644 index 00000000..6d00c7bc Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/explorer2140.png differ diff --git a/session-demos/2019/odtvscodescreenshots/explorer2340.png b/session-demos/2019/odtvscodescreenshots/explorer2340.png new file mode 100644 index 00000000..db4c278d Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/explorer2340.png differ diff --git a/session-demos/2019/odtvscodescreenshots/formatter.png b/session-demos/2019/odtvscodescreenshots/formatter.png new file mode 100644 index 00000000..09e148ab Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/formatter.png differ diff --git a/session-demos/2019/odtvscodescreenshots/formatter2160.png b/session-demos/2019/odtvscodescreenshots/formatter2160.png new file mode 100644 index 00000000..4b5bea90 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/formatter2160.png differ diff --git a/session-demos/2019/odtvscodescreenshots/hover.png b/session-demos/2019/odtvscodescreenshots/hover.png new file mode 100644 index 00000000..255ecbed Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/hover.png differ diff --git a/session-demos/2019/odtvscodescreenshots/ociexplorer.png b/session-demos/2019/odtvscodescreenshots/ociexplorer.png new file mode 100644 index 00000000..644977da Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/ociexplorer.png differ diff --git a/session-demos/2019/odtvscodescreenshots/ociexplorer2150.png b/session-demos/2019/odtvscodescreenshots/ociexplorer2150.png new file mode 100644 index 00000000..85498de5 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/ociexplorer2150.png differ diff --git a/session-demos/2019/odtvscodescreenshots/peek.gif b/session-demos/2019/odtvscodescreenshots/peek.gif new file mode 100644 index 00000000..f191b280 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/peek.gif differ diff --git a/session-demos/2019/odtvscodescreenshots/peekmenu.png b/session-demos/2019/odtvscodescreenshots/peekmenu.png new file mode 100644 index 00000000..7aa8f225 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/peekmenu.png differ diff --git a/session-demos/2019/odtvscodescreenshots/peekmenu2150.png b/session-demos/2019/odtvscodescreenshots/peekmenu2150.png new file mode 100644 index 00000000..7fd2158c Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/peekmenu2150.png differ diff --git a/session-demos/2019/odtvscodescreenshots/peekscreen.png b/session-demos/2019/odtvscodescreenshots/peekscreen.png new file mode 100644 index 00000000..0e84c8d4 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/peekscreen.png differ diff --git a/session-demos/2019/odtvscodescreenshots/readme b/session-demos/2019/odtvscodescreenshots/readme new file mode 100644 index 00000000..7fb69470 --- /dev/null +++ b/session-demos/2019/odtvscodescreenshots/readme @@ -0,0 +1 @@ +Please talk to christianshay before deleting or moving this directory. Thank you! diff --git a/session-demos/2019/odtvscodescreenshots/readmeoverview2130.png b/session-demos/2019/odtvscodescreenshots/readmeoverview2130.png new file mode 100644 index 00000000..30d07ad3 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/readmeoverview2130.png differ diff --git a/session-demos/2019/odtvscodescreenshots/readmeoverview2150.png b/session-demos/2019/odtvscodescreenshots/readmeoverview2150.png new file mode 100644 index 00000000..1bb63112 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/readmeoverview2150.png differ diff --git a/session-demos/2019/odtvscodescreenshots/selectai.gif b/session-demos/2019/odtvscodescreenshots/selectai.gif new file mode 100644 index 00000000..f191b280 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/selectai.gif differ diff --git a/session-demos/2019/odtvscodescreenshots/selectai.png b/session-demos/2019/odtvscodescreenshots/selectai.png new file mode 100644 index 00000000..9e2877c6 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/selectai.png differ diff --git a/session-demos/2019/odtvscodescreenshots/sqlmonitorlist.png b/session-demos/2019/odtvscodescreenshots/sqlmonitorlist.png new file mode 100644 index 00000000..c0fc6ca6 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/sqlmonitorlist.png differ diff --git a/session-demos/2019/odtvscodescreenshots/sqlmonitorreport.png b/session-demos/2019/odtvscodescreenshots/sqlmonitorreport.png new file mode 100644 index 00000000..7889c5c6 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/sqlmonitorreport.png differ diff --git a/session-demos/2019/odtvscodescreenshots/testproc2130.png b/session-demos/2019/odtvscodescreenshots/testproc2130.png new file mode 100644 index 00000000..1cb38199 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/testproc2130.png differ diff --git a/session-demos/2019/odtvscodescreenshots/testproc2140.png b/session-demos/2019/odtvscodescreenshots/testproc2140.png new file mode 100644 index 00000000..be631ac4 Binary files /dev/null and b/session-demos/2019/odtvscodescreenshots/testproc2140.png differ diff --git a/session-demos/2021/oracle-db-world/README.md b/session-demos/2021/oracle-db-world/README.md new file mode 100644 index 00000000..a2a24330 --- /dev/null +++ b/session-demos/2021/oracle-db-world/README.md @@ -0,0 +1,5 @@ +This directory contains demo code and pointers to the **What’s New for .NET and Visual Studio Code Developers in Oracle Database 21c** session at Oracle Database World 2021. The following demos were presented with links to their source code: +* [ODP.NET and .NET 6 console app](https://github.com/oracle/dotnet-db-samples/blob/master/session-demos/2021/oracle-db-world/odp-dotnet6.cs) +* [Oracle Entity Framework Core 6 console app](https://github.com/oracle/dotnet-db-samples/blob/master/session-demos/2021/oracle-db-world/odp-efcore6.cs) +* [ODP.NET User-Defined Types (managed and core) console apps](https://github.com/oracle/dotnet-db-samples/tree/master/samples/udt) +* [ODP.NET Binary JSON and Client Initiated Continuous Query Notification (CICQN) console app](https://github.com/oracle/dotnet-db-samples/tree/master/session-demos/2021/cicqn-json) diff --git a/session-demos/2021/oracle-db-world/odp-dotnet6.cs b/session-demos/2021/oracle-db-world/odp-dotnet6.cs new file mode 100644 index 00000000..58758e81 --- /dev/null +++ b/session-demos/2021/oracle-db-world/odp-dotnet6.cs @@ -0,0 +1,72 @@ +using System; +using Oracle.ManagedDataAccess.Client; + +namespace DotNet6_ODP.NET_Demo +{ + class Program + { + static void Main(string[] args) + { + + Console.WriteLine(); + Console.WriteLine("This app is using .NET version: {0}", Environment.Version.ToString()); + Console.WriteLine(); + + //Demo: ODP.NET Core application that connects to Oracle Autonomous DB or on-premises DB + + //Enter user id and password, such as ADMIN user + string conString = "User Id=;Password=;" + + + //Enter net service name, EZ Connect, or TNS connection string for data source value + "Data Source=;"; + + using (OracleConnection con = new OracleConnection(conString)) + { + using (OracleCommand cmd = con.CreateCommand()) + { + try + { + //Uncomment and enter directory the tnsnames.ora and sqlnet.ora files are located, if applicable + //OracleConfiguration.TnsAdmin = @""; + //Uncomment and enter directory where wallet is stored locally, if applicable + //OracleConfiguration.WalletLocation = @""; + + con.Open(); + + Console.WriteLine("Successfully connected to Oracle Autonomous Database"); + + //Retrieve database version info + cmd.CommandText = "SELECT BANNER FROM V$VERSION"; + OracleDataReader reader = cmd.ExecuteReader(); + reader.Read(); + Console.WriteLine("The version is " + reader.GetString(0)); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + } + } + } + } +} + +/* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/session-demos/2021/oracle-db-world/odp-efcore6.cs b/session-demos/2021/oracle-db-world/odp-efcore6.cs new file mode 100644 index 00000000..2f250455 --- /dev/null +++ b/session-demos/2021/oracle-db-world/odp-efcore6.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; + +namespace OracleEFCore +{ + class Program + { + + public class BloggingContext : DbContext + { + public DbSet? Blogs { get; set; } + public DbSet? Posts { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + //Enter user id, passowrd, and data source info + optionsBuilder.UseOracle(@"User Id=;Password=;Data Source="); + } + } + + public class Blog + { + public int BlogId { get; set; } + public string? Url { get; set; } + public int Rating { get; set; } + public List? Posts { get; set; } + } + + public class Post + { + public int PostId { get; set; } + public string? Title { get; set; } + public string? Content { get; set; } + + public int BlogId { get; set; } + public Blog? Blog { get; set; } + } + + static void Main(string[] args) + { + Console.WriteLine("This app is using .NET version: {0}", Environment.Version.ToString()); + Console.WriteLine(); + + using (var db = new BloggingContext()) + { + var blog = new Blog { Url = "https://blogs.oracle.com" }; + db.Blogs!.Add(blog); + db.SaveChanges(); + } + + Console.WriteLine("Here are the Blog URLs in the database:"); + using (var db = new BloggingContext()) + { + var blogs = db.Blogs; + foreach (var item in blogs!) + { + Console.WriteLine(item.Url); + } + } + } + } +} + +/* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/session-demos/2022/oracle-cloudworld/README.md b/session-demos/2022/oracle-cloudworld/README.md new file mode 100644 index 00000000..b4acd8e3 --- /dev/null +++ b/session-demos/2022/oracle-cloudworld/README.md @@ -0,0 +1,18 @@ +This directory contains pointers to the Oracle .NET session demo code or tutorials during [Oracle CloudWorld](https://www.oracle.com/cloudworld/) 2022. The following demos were shown: + +**What’s New for Oracle .NET and Entity Framework Core Developers** +* [Oracle EF Core 6 and Oracle EF Core 7 console app](https://github.com/oracle/dotnet-db-samples/tree/master/samples/ef-core/get-started) + * Note: The same demo code was used for both demos with the Oracle and EF Core assemblies updated to use either version 6 or 7. +* [ODP.NET Async](https://github.com/oracle/dotnet-db-samples/blob/master/session-demos/2022/oracle-cloudworld/async-odpnet.cs) vs. [ODP.NET Sync](https://github.com/oracle/dotnet-db-samples/blob/master/session-demos/2022/oracle-cloudworld/sync-odpnet.cs) +* [ODP.NET User-Defined Types (managed and core) console apps](https://github.com/oracle/dotnet-db-samples/tree/master/samples/udt) +* [ODP.NET Binary JSON and Client Initiated Continuous Query Notification (CICQN) console app](https://github.com/oracle/dotnet-db-samples/tree/master/session-demos/2021/cicqn-json) + +**Using Oracle Autonomous Database with Microsoft Power BI in the Multicloud** +* [Power BI Desktop: Connecting to Oracle Autonomous Database and On-premises Database](https://www.oracle.com/a/ocom/docs/database/microsoft-powerbi-connection-adw.pdf) +* [Power BI Service: Connecting to Oracle Autonomous Database and On-premises Database](https://www.oracle.com/a/ocom/docs/database/microsoft-powerbi-service-gateway-adw.pdf) + +**Multicloud Development with Azure and Oracle Database Cloud** +* [Azure ASP.NET Core 6 web app for Oracle Autonomous Database](https://github.com/oracle/dotnet-db-samples/blob/master/samples/asp.net-core/6/Program.cs) + +**.NET Development with Oracle Autonomous Database Quick Start** +* [.NET Development with Oracle Autonomous Database LiveLab](https://apexapps.oracle.com/pls/apex/dbpm/r/livelabs/view-workshop?wid=3359) diff --git a/session-demos/2022/oracle-cloudworld/async-odpnet.cs b/session-demos/2022/oracle-cloudworld/async-odpnet.cs new file mode 100644 index 00000000..5107b52e --- /dev/null +++ b/session-demos/2022/oracle-cloudworld/async-odpnet.cs @@ -0,0 +1,62 @@ +using Oracle.ManagedDataAccess.Client; + +// This app measures how long it takes asynchronous ODP.NET operations. +class ODPNET_Async +{ + public static async Task Main() + { + // Modify User Id, Password, and Data Source as needed to connect + string conString = "User Id=hr;Password=;Data Source=;"; + + using (OracleConnection con = new OracleConnection(conString)) + { + DateTime start_time = DateTime.Now; + Task task = con.OpenAsync(); + DateTime end_time_open = DateTime.Now; + + // Simulate operation that takes one second + Thread.Sleep(1000); + + string cmdText = "SELECT * FROM EMPLOYEES FETCH FIRST 1 ROWS ONLY"; + using (OracleCommand cmd = new OracleCommand(cmdText, con)) + { + // Get open connection + await task; + using (OracleDataReader reader = await cmd.ExecuteReaderAsync()) + { + await reader.ReadAsync(); + } + } + DateTime end_time_all = DateTime.Now; + + // Calculate connection open time + TimeSpan ts_open = end_time_open - start_time; + double ts_open1 = Math.Round(ts_open.TotalSeconds, 2); + Console.WriteLine("Asynchronous connection open time: " + ts_open1 + " seconds"); + + // Calculate overall operation time + TimeSpan ts_all = end_time_all - start_time; + double ts_all1 = Math.Round(ts_all.TotalSeconds, 2); + Console.WriteLine("Asynchronous ODP.NET operations time: " + ts_all1 + " seconds"); + } + } +} + +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ diff --git a/session-demos/2022/oracle-cloudworld/sync-odpnet.cs b/session-demos/2022/oracle-cloudworld/sync-odpnet.cs new file mode 100644 index 00000000..791f0213 --- /dev/null +++ b/session-demos/2022/oracle-cloudworld/sync-odpnet.cs @@ -0,0 +1,61 @@ +using Oracle.ManagedDataAccess.Client; + +// This app measures how long it takes synchronous ODP.NET operations. +class ODPNET_Sync +{ + static void Main() + { + // Modify User Id, Password, and Data Source as needed to connect + string conString = "User Id=hr;Password=;Data Source=;"; + + using (OracleConnection con = new OracleConnection(conString)) + { + DateTime start_time = DateTime.Now; + con.Open(); + DateTime end_time_open = DateTime.Now; + + // Simulate operation that takes one second + Thread.Sleep(1000); + + string cmdText = "SELECT * FROM EMPLOYEES FETCH FIRST 1 ROWS ONLY"; + using (OracleCommand cmd = new OracleCommand(cmdText, con)) + { + using (OracleDataReader reader = cmd.ExecuteReader()) + { + reader.Read(); + } + } + DateTime end_time_all = DateTime.Now; + + // Calculate connection open time + TimeSpan ts_open = end_time_open - start_time; + double ts_open1 = Math.Round(ts_open.TotalSeconds, 2); + Console.WriteLine("Synchronous connection open time: " + ts_open1 + " seconds"); + + // Calculate overall operation time + TimeSpan ts_all = end_time_all - start_time; + double ts_all1 = Math.Round(ts_all.TotalSeconds, 2); + Console.WriteLine("Synchronous ODP.NET operations time: " + ts_all1 + " seconds"); + } + } +} + + +/* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ + +/****************************************************************************** + * + * You may not use the identified files except in compliance with The MIT + * License (the "License.") + * + * You may obtain a copy of the License at + * https://github.com/oracle/Oracle.NET/blob/master/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/