Заполнение нескольких таблиц данных с помощью 1 OracleCommand

#.net #performance #oracle #dataset

#.net #Производительность #Oracle #набор данных

Вопрос:

Я нашел несколько вопросов / ответов на SOF о том, как запускать несколько запросов к Oracle (начальный конечный блок, анонимная хранимая процедура). Я хочу сделать практически то же самое, но я хочу, чтобы эти запросы заполняли несколько таблиц данных «за один раз»:

Итак, вместо нашего обычного: один запрос на DataTable like (это «псевдокод», а не рабочий пример!)

 Odp.Fill(SomeQuery, SomeDataTable, SomeParameters);
  

Я хотел бы сделать что-то вроде

 Odp.Fill(
   new Query(SomeQuery, SomeDataTable, SomeParameters),
   new Query(SomeQuery2, SomeDataTable2, SomeParameters),
   ...)
  

Комментарии:

1. Почему вы хотите использовать один вызов вместо нескольких? Это из-за простоты использования, ожидания значительного увеличения производительности, атомарного выполнения, обработки транзакций, обработки ошибок и т.д.?

2. > «ожидание (значительного) увеличения производительности» Реализация этого нового метода «BulkFill» также была бы хорошим моментом для добавления (пользовательский? т.е. Обработка ошибок нового запроса (sql, dt, customErrMsg)), уменьшение объема кода DAL, улучшение «читаемости» методов заполнения, …

Ответ №1:

Это только один из многих способов, которыми вы могли бы получить несколько таблиц в одном запросе.

PL / SQL

 CREATE OR REPLACE PACKAGE getBldgRoom AS

/******************************************************************************

   NAME:       getBldgRoom
   PURPOSE:

   REVISIONS:
   Ver        Date        Author           Description
   ---------  ----------  ---------------  ------------------------------------
   1.0        2011-5-27    has986       1. Created this package.

******************************************************************************/

PROCEDURE getBldgRoom(rcBuildingData OUT SYS_REFCURSOR, rcRoomData OUT SYS_REFCURSOR);


END getBldgRoom;

/

CREATE OR REPLACE PACKAGE BODY GETBLDGROOM AS
PROCEDURE getBldgRoom(rcBuildingData OUT SYS_REFCURSOR, rcRoomData OUT SYS_REFCURSOR) IS
  BEGIN
        OPEN rcBuildingData FOR
              select bldg_code, bldg_desc  from IH_CSI_OWNER.BUILDING;

        OPEN rcRoomData FOR
              select bldg_code, room_code, room_desc from IH_CSI_OWNER.ROOM;
  END getBldgRoom;

END GETBLDGROOM;

/
  

Код на C #

 using System;
using System.Data;
using Oracle.DataAccess.Client; //Needs Oracle Data Access Client (ODAC)

namespace ClassLibrary
{
    public class TwoTableDataSet
    {
        public DataSet getTwoTables()
        {
            OracleConnection conn = new OracleConnection();

            //Normally we get the connection string from the web.config file or the app.config file
            conn.ConnectionString = "Persist Security Info=False;User Id=*USER_NAME*;Password=*USER_PASSWORD*;Data Source=*DataBaseName*";
            DataSet ds = new DataSet();

            try
            {
                conn.Open();

                //------------------------------------------------------------------------------------------------------
                //Set up the select command
                OracleCommand cmd = new OracleCommand();
                cmd.BindByName = true; //If you do not bind by name, you must add parameters in the same order as they are listed in the procedure signature.
                cmd.Connection = conn;
                cmd.CommandType = CommandType.StoredProcedure;  //A procedure in an oracle package
                cmd.CommandText = "GETBLDGROOM.GetBldgRoom"; //The name of the procedure

                cmd.Parameters.Add("rcBuildingData", OracleDbType.RefCursor, ParameterDirection.Output);
                cmd.Parameters.Add("rcRoomData", OracleDbType.RefCursor, ParameterDirection.Output);

                OracleDataAdapter da = new OracleDataAdapter();
                da.SelectCommand = cmd;

                //------------------------------------------------------------------------------------------------------

                //get the data from the two tables in the procedure
                da.Fill(ds);
                //ds now contains ds.Tables[0] and ds.Tables[1]

                //Let's give them names
                ds.Tables[0].TableName = "BUILDINGS";
                ds.Tables[1].TableName = "ROOMS";

                //Let's add a relationship between the two tables
                DataColumn parentColumn = ds.Tables["BUILDINGS"].Columns["BLDG_CODE"];
                DataColumn childColumn = ds.Tables["ROOMS"].Columns["BLDG_CODE"];
                DataRelation dr = new System.Data.DataRelation( "BuildingsRooms", parentColumn, childColumn);
                ds.Relations.Add(dr);
            }
            catch (Exception ex)
            {
                //Add a breakpoint here to view the exception
                //Normally the exception would be written to a log file or EventLog in the case of a Web app
                //Alternatively, it could be sent to a WebService which logs errors and then it could work for both Web or Windows apps
                Exception lex = ex;
            }
            finally
            {
                if (conn.State == ConnectionState.Open)
                {
                    conn.Close();
                }
            }

            return ds;
        }
    }
}
  

Надеюсь, это поможет

Харви Сатер

Комментарии:

1. Идеальный. Это было именно то, что мне было нужно для решения моей проблемы.

2. Обратите внимание, что порядок таблиц в наборе данных ds соответствует порядку, в котором параметры добавляются в OracleCommand . Это может отличаться от порядка формальных параметров, определенных в хранимой процедуре.