Overview

ODP.NET offers faster and reliable access to Oracle Database by using Oracle Native APIs. ODP.NET provides features to access any .NET application. The data access through ODP.NET can be done using a collection of classes contained in Oracle.DataAccess assembly.

DataSet is a major component of ADO.NET. It is an in-memory cache of the data retrieved from the database. OracleDataAdapter represents a set of data commands and a database connection that is used to fill the DataSet based on the query given.

OracleCommand represents SQL statements to execute against datasource. OracleConnection is used to build the database connection.

OracleDataReader is a read-only, forward-only recordset. ExecuteReader method of OracleCommand is used to create OracleDataReader. OracleBLOB is an OracleType specific to ODP.NET for accessing BLOB data from Oracle databases.

Example

The purpose of this sample application is to demonstrate:

  1. How to perform DML operations on DataSet for LOB (Large Objects) columns like images,
    sound files etc. through ODP.NET using C#.
     
  2. How to fetch BLOB data using OracleBLOB (ODP.NET type) and OracleDataReader
    through ODP.NET using C#

The scenario for this sample application is to insert or update new photos for the employees in the "EMP" table. When this application is run, a drop down list populated with employee data from database is displayed. The user can select the employee for which he/she wishes to insert/update a photo and her/his job title. To insert/update the photo and job title the user can enter text for the job and select an image for the photo by clicking on 'Browse' button. To commit changes the user can click on 'Save' button.

/**********************************************************************************
* This sample application shows how to perform DML operations on a DataSet for LOB
* (Large Objects) columns like images, sound files etc. through ODP.NET using C#.
*
* The connection to database is made using Oracle Data Provider for .Net (ODP .Net).
* DataSet is an in-memory cache of data that contains data filled by an
* OracleDataAdapter.
* An OracleDataAdapter serves as a bridge between the DataSet and the data source.
* The connection to database is made using OracleConnection object.
*
* The scenario for this sample application is to insert or update new photos for
* the employees in the "EMP" table.
* When this application is run, a drop down list populated with employee data
* from database is displayed. The user can select the employee for which he/she
* wishes to insert/update a Photo and her/his Job Title.
*
* To insert/update the Photo and Job Title the user can enter text for
* Job and select image for the photo by clicking on 'Browse' button.
* To commit changes the user can click on 'Save' button.
**********************************************************************************/

// Standard Namespaces referenced in this sample application
using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;

// Namespace for ODP.Net classes
using Oracle.DataAccess.Client;

// Namespace for ODP.Net Types
using Oracle.DataAccess.Types;

namespace Akadia.OraBlobs
{
    // ManipulateOraBlobs class inherits Window's Form
    public class ManipulateOraBlobs : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button saveBtn;
        private System.Windows.Forms.Button closeBtn;
        private System.Windows.Forms.Button browseBtn;
        private Container components = null;

        // Variable for storing the image name, path chosen from file dialog
        private String  _strImageName = "";

        // To store value of current Employee ID
        private String _curEmpNo = "";

        // To store existing Employee Job Title
        private String _strExistText = "";

        // To store existing Employee values
        private int _empID = 0;
        private int _imageLength;
        private byte[] _imageData;
        private System.Windows.Forms.Label lblJob;
        private System.Windows.Forms.Label lblEmpName;
        private System.Windows.Forms.ComboBox cboEmpName;
        private System.Windows.Forms.TextBox txtEmpJob;
        private System.Windows.Forms.PictureBox picEmpPhoto;

        // For database connection
        private OracleConnection _conn;

        // Constructor
        public ManipulateOraBlobs()
        {
            // Creates the UI required for this application
            InitializeComponent();
        }

        // ***************************************************************
        // Entry point to this sample application
        // ***************************************************************

        static void Main()
        {
            // Instantiating this class
            ManipulateOraBlobs oraBlobs = new ManipulateOraBlobs();

            // Get database connection
            if (oraBlobs.getDBConnection())
            {
                // Populate Employee Names in the ComboBox
                oraBlobs.populateComboBox();

                // When this application is run, "ManipulateOraBlobs' form is run
                Application.Run(oraBlobs);
            }
        }

        // *******************************************************************
        // Get the database connection using the parameters given.
        // Note: Replace the datasource parameter with your datasource value
        // in ConnectionParams.cs file.
        // *******************************************************************

        private Boolean getDBConnection()
        {
            try
            {
                // Connection Information
                string connectionString =

                    // Username
                    "User Id=" + ConnectionParams.Username +

                    // Password
                    ";Password=" + ConnectionParams.Password +

                    // Replace with your datasource value (TNSNames)
                    ";Data Source=" + ConnectionParams.Datasource ;

                // Connection to datasource, using connection parameters given above
                _conn = new OracleConnection(connectionString);

                // Open database connection
                _conn.Open();
                return true;
            }
            // Catch exception when error in connecting to database occurs
            catch (Exception ex)
            {
                // Display error message
                MessageBox.Show(ex.ToString());
                return false;
            }
        }

        // ***********************************************************************
        // Populate Employee Names in the ComboBox with data from the "EMP"
        // table. 'EmpName' is displayed in the List, whereas the actual value
        // stored is 'EmpNo'.
        // ***********************************************************************

        void populateComboBox()
        {
            // To fill DataSet and update datasource
            OracleDataAdapter empAdapter;

            // In-memory cache of data
            DataSet empDataSet;

            // No selection
            // The starting position of text selected in the text box.

            txtEmpJob.SelectionStart = 0;

            try
            {
                // Instantiate OracleDataAdapter to create DataSet
                empAdapter = new OracleDataAdapter();

                // Fetch Product Details
                empAdapter.SelectCommand = new OracleCommand
                    ("SELECT empno, ename FROM emp ORDER BY ename ASC",_conn);

                // Instantiate a DataSet object
                empDataSet = new DataSet("empDataSet");

                // Fill the DataSet
                empAdapter.Fill(empDataSet, "emp");

                // Employee Name is shown in the list displayed
                cboEmpName.DisplayMember = empDataSet.Tables["emp"].Columns["ename"].ToString();

                // Employee Id is the actual value contained in the list
                cboEmpName.ValueMember = empDataSet.Tables["emp"].Columns["empno"].ToString();

                // Assign DataSet as a data source for the Combo Box
                cboEmpName.DataSource = empDataSet.Tables["emp"].DefaultView;
            }
            catch(Exception ex)
            {
                // Display error message
                System.Windows.Forms.MessageBox.Show(ex.ToString());
            }
        }

        // *******************************************************************
        // This method is called on the click event of the 'Browse' button,
        // The purpose of this method is to display a File-Dialog, from
        // which the user can choose the desired photo for the employee.
        // The chosen image gets displayed in the Picture Box.
        // *******************************************************************

        private void browseBtn_Click(object sender, System.EventArgs e)
        {
            try
            {
                // Instantiate File Dialog box
                FileDialog fileDlg = new OpenFileDialog();

                // Set the initial directory
                fileDlg.InitialDirectory =
                "E:\\MyDotNet\\MyWinFormsTutorial\\OraEmpWithBlob\\doc\\images" ;

                // Filter image(.jpg, .bmp, .gif) files only
                fileDlg.Filter = "Image File (*.jpg;*.bmp;*.gif)|*.jpg;*.bmp;*.gif";

                // Restores the current directory before closing
                fileDlg.RestoreDirectory = true ;

                // When file is selected from the File Dialog
                if(fileDlg.ShowDialog() == DialogResult.OK)
                {
                    // Store the name of selected file into a variable
                    _strImageName = fileDlg.FileName;

                    // Create a bitmap for selected image
                    Bitmap newImage= new Bitmap(_strImageName);

                    // Fit the image to the size of picture box
                    picEmpPhoto.SizeMode = PictureBoxSizeMode.StretchImage;

                    // Show the bitmap in picture box
                    picEmpPhoto.Image = (Image)newImage;
                }

                // No Image chosen
                fileDlg = null;
            }
            catch(System.ArgumentException ex)
            {
                // Display error message, if image is invalid
                _strImageName = "";
                System.Windows.Forms.MessageBox.Show(ex.ToString());
            }
            catch(Exception ex)
            {
                // Display error message
                System.Windows.Forms.MessageBox.Show(ex.ToString());
            }
        }

        // *******************************************************************************
        // This method is called on the click event of the 'Save' button,
        // It calls "updateData" method for data updation of Job and Photos.
        // *******************************************************************************

        private void saveBtn_Click(object sender, System.EventArgs e)
        {
            this.updateData();
        }

        // *****************************************************************************
        // This method is called from the click event of Save button and
        // SelectedIndexChanged event of Products DropDown list.
        //
        // The purpose of this method is to demonstrate DML operations on a Data Set for
        // LOB(Large Object)data. The functionalitity of this method is to insert
        // a new employee photo or update an existing one.
        //
        // The flow of this method is as follows:
        // 1. Instantiate an OracleDataAdapter object with the query for 'emp'
        //    table.
        // 2. Configure the schema to match with Data Source. Set Primary Key information.
        // 3. OracleCommandBuilder automatically generates the command for loading data
        //    for the given query.
        // 4. The Dataset is filled with data that is loaded through OracleDataAdapter.
        // 5. Create a DataRow in a DataTable contained in the DataSet for a new
        //    photo or find the current DataRow for the existing photo.
        // 6. Convert new the photo image into a byte array.
        // 7. Assign the corresponding values to the columns in the Data Row.
        // 8. Add the Data Row to the Data Set for a new photo or end the edit
        //    operation for existing photo.
        // 9. Update the database with the Data Set values. Hence adding/updating
        //    'emp' table data.
        // *************************************************************************

        private void updateData()
        {
            try
            {
                // Check if Image or Text is changed.
                if (_strImageName != "" || _strExistText != txtEmpJob.Text)
                {
                    // Change the default cursor to 'WaitCursor'(an HourGlass)
                    this.Cursor = Cursors.WaitCursor;

                    // Change the default cursor to 'WaitCursor'(an HourGlass)
                    this.Cursor = Cursors.WaitCursor;

                    // To fill Dataset and update datasource
                    OracleDataAdapter empAdapter;

                    // In-memory cache of data
                    DataSet empDataSet;

                    // Data Row contained in Data Table
                    DataRow empRow;

                    // FileStream to get the Employee Photo
                    FileStream fs;

                    // Get Image Data from the Filesystem if User has loaded a Photo
                    // by the 'Browse' button

                    if (_strImageName != "")
                    {
                        fs = new FileStream(@_strImageName, FileMode.Open,FileAccess.Read);
                        _imageLength = (int)fs.Length;

                        // Create a byte array of file stream length
                        _imageData = new byte[fs.Length];

                        // Read block of bytes from stream into the byte array
                        fs.Read(_imageData,0,System.Convert.ToInt32(fs.Length));

                        // Close the File Stream
                        fs.Close();
                    }

                    // Instantiate an OracleDataAdapter object with the
                    // appropriate query

                    empAdapter = new OracleDataAdapter(
                        "SELECT empno, ename, job, photo" +
                        "  FROM emp WHERE empno = " + _curEmpNo, _conn);

                    // Instantiate a DataSet object
                    empDataSet= new DataSet("emp");

                    // Create an UPDATE command as a template for the
                    // OracleDataAdapter.

                    empAdapter.UpdateCommand = new OracleCommand
                        ("UPDATE emp SET " +
                        "job = :iJOB, "+
                        "photo = :iPHOTO " +
                        "WHERE empno = :iEMPNO", _conn);

                    // Add the Parameters for the UPDATE Command
                    empAdapter.UpdateCommand.Parameters.Add(":iJOB",
                       OracleDbType.Varchar2, 9, "job");
                    empAdapter.UpdateCommand.Parameters.Add(":iPHOTO",
                       OracleDbType.Blob, _imageLength, "photo");
                    empAdapter.UpdateCommand.Parameters.Add(":iEMPNO",
                       OracleDbType.Int16, 0, "empno");


                    // Configure the schema to match with the Data Source.
                    // AddWithKey sets the Primary Key information to complete the
                    // schema information

                    empAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;

                    // Configures the schema to match with Data Source
                    empAdapter.FillSchema(empDataSet, SchemaType.Source, "emp");

                    // Fills the DataSet with 'EMP' table data
                    empAdapter.Fill(empDataSet,"emp");

                    // Get the current Employee ID row for updation
                    DataTable empTable = empDataSet.Tables["emp"];
                    empRow = empTable.Rows.Find(_curEmpNo);

                    // Start the edit operation on the current row in
                    // the 'emp' table within the dataset.

                    empRow.BeginEdit();

                    // Assign the value of the Job Title
                    empRow["job"] = txtEmpJob.Text;

                    // Assign the value of the Photo if not empty
                    if (_imageData.Length != 0)
                    {
                        empRow["photo"] = _imageData;
                    }

                    // End the editing current row operation
                    empRow.EndEdit();

                    // Update the database table 'EMP'
                    empAdapter.Update(empDataSet,"emp");

                    // Reset variables
                    _strImageName = "";
                    _strExistText = txtEmpJob.Text;

                    // Set the wait cursor to default cursor
                    this.Cursor = Cursors.Default;

                    // Display message on successful data updatation
                    MessageBox.Show("Data saved successfully");
                }
                else
                {
                    MessageBox.Show("Select Photo or change Job Title for the Employee");
                }
            }
            catch(Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.ToString());
            }
        }

        // ***********************************************************************
        // This method is called when an Item is selected from 'cboEmpName'
        // drop down list. The purpose of this method is to demonstrate how to
        // fetch BLOB lob as an OracleLOB (ODP .Net Data Type) using an
        // OracleDataReader.
        // The flow of the method is as follows:
        // 1. Clear the contents of Job-Title and Photo.
        // 2. Populate OracleDataReader with data from 'EMP' table, through
        //    ExecuteReader method of OracleCommand object. The data is fetched
        //    based on the Emplyoyy selected from 'cboEmpName' list.
        // 3. Assign value for Job-Title from the OracleDataReader.
        // 4. The Image(BLOB) is read into a Byte array, then used to construct
        //    MemoryStream and passed to PictureBox.

        // ***********************************************************************
        private void cboEmpName_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            // For fetching read only rows from datasource
            OracleDataReader oraImgReader;

            // For executing SQL statements against datasource
            OracleCommand oraImgCmd;

            // To store MessageBox result
            DialogResult x;

            // If Image orText is changed then promt user to save.
            if (_strImageName != "" || _strExistText != txtEmpJob.Text)
            {
                // MessageBox prompting user whether he/she wishes to save changes made
                x = MessageBox.Show("Do you want to save changes ?",
                    "Save Dialog",MessageBoxButtons.YesNo);

                // If the user wishes to save changes
                if (x == DialogResult.Yes)
                {
                    // Call the method for insertion or updation
                    updateData();

                    // Reset variable
                    _empID =  int.Parse(cboEmpName.GetItemText(cboEmpName.SelectedValue));
                }

                    // If the user doesn't wish to save changes
                else
                {
                    // Reset variables
                    _strImageName ="";
                    _empID =  int.Parse(cboEmpName.GetItemText(cboEmpName.SelectedValue));
                }
            }
            try
            {
                // Initializing, clear contents
                txtEmpJob.Text ="";
                picEmpPhoto.Image = null;
                _strImageName = "";
                _curEmpNo ="";
                _strExistText="";

                // Fetch Product Details using OracleCommand
                // for the selected Product from the Combobox

                string strSelectedId = cboEmpName.GetItemText(cboEmpName.SelectedValue);
                oraImgCmd = new OracleCommand(
                    "SELECT " +
                    "empno, " +
                    "job, " +
                    "photo  " +
                    "FROM emp " +
                    "WHERE empno = " + strSelectedId ,_conn);

                // Set OracleConnection for this instance of OracleCommand
                oraImgCmd.Connection = _conn;

                // Set Command type as text
                oraImgCmd.CommandType = CommandType.Text;

                // Sends the CommandText to the Connection
                // and builds an OracleDataReader

                oraImgReader = oraImgCmd.ExecuteReader();

                // Read data
                // Returns true if another row exists; otherwise, returns false.

                Boolean recordExist = oraImgReader.Read();

                // If data exists
                if (recordExist)
                {
                    // Store current Employee value
                    if (!oraImgReader.IsDBNull(0))
                    {
                        _curEmpNo = oraImgReader.GetInt32(0).ToString();
                    }

                    // Assign Job-Title to the Text Box
                    if (oraImgReader.GetValue(1).ToString() != "")
                    {
                        _strExistText =  oraImgReader.GetString(1);
                        txtEmpJob.Text = _strExistText;
                    }

                    // If Photo exists in the Database, load it into the PictureBox
                    if (oraImgReader.GetValue(2).ToString() != "")
                    {
                        // Fetch the BLOB data through OracleDataReader using OracleBlob type
                        OracleBlob blob = oraImgReader.GetOracleBlob(2);

                        // Create a byte array of the size of the Blob obtained
                        Byte[] byteArr =  new Byte[blob.Length];

                        // Read blob data into byte array
                        int i = blob.Read(byteArr,0,System.Convert.ToInt32(blob.Length));

                        // Get the primitive byte data into in-memory data stream
                        MemoryStream memStream = new MemoryStream(byteArr);

                        // Attach the in-memory data stream to the PictureBox
                        picEmpPhoto.Image = Image.FromStream(memStream);

                        // Fit the image to the PictureBox size
                        picEmpPhoto.SizeMode = PictureBoxSizeMode.StretchImage;
                    }
                    // close the OracleDataReader
                    oraImgReader.Close();
                }

                // Reset  variable
                _empID =  int.Parse(cboEmpName.GetItemText(cboEmpName.SelectedValue));
            }

            // Catch exception when accessing arrary element out of bound
            catch (System.IndexOutOfRangeException rangeException)
            {
                // Do nothing
                rangeException.ToString();
            }
            catch (Exception ex)
            {
                // Display error message
                System.Windows.Forms.MessageBox.Show( ex.ToString());
            }
        }

        // **********************************************************************
        // This method is called on the click event of the 'Close' button.
        // The purpose of this method is to close the database connection,
        // the form 'ManipulateOraBlobs' and then exit out of the application.
        // **********************************************************************

        private void closeBtn_Click(object sender, System.EventArgs e)
        {
            _conn.Close();
            this.Close();
            Application.Exit();
        }
       .....
       .....

    }
}