Oracle
 sql >> база данни >  >> RDS >> Oracle

Използване на Dapper QueryMultiple в Oracle

Оперативната програма вероятно отдавна е решила проблема досега, но към момента на писане този въпрос има само един отговор и всъщност не решава проблема с използването на QueryMultiple() на Dapper метод с Oracle. Както @Kamolas81 правилно заявява, като се използва синтаксисът от официалните примери, човек наистина ще получи ORA-00933: SQL command not properly ended съобщение за грешка. Прекарах известно време в търсене на някакъв вид документация за това как да направя QueryMultiple() с Oracle, но бях изненадан, че няма наистина едно място, което да има отговор. Бих си помислил, че това е доста често срещана задача. Мислех, че ще публикувам отговор тук, за да ме спаси :) някой в ​​бъдеще, в случай че някой случайно има същия проблем.

Dapper изглежда просто предава SQL командата направо към ADO.NET и който и да е db доставчик изпълнява командата. В синтаксиса от примерите, където всяка команда е разделена с прекъсване на ред, SQL сървърът ще интерпретира това като множество заявки за изпълнение към базата данни и ще изпълни всяка от заявките и ще върне резултатите в отделни изходи. Не съм експерт по ADO.NET, така че може да бъркам терминологията, но крайният ефект е, че Dapper получава множество изходни данни на заявката и след това прави своята магия.

Oracle обаче не разпознава множеството заявки; той смята, че SQL командата е неправилно форматирана и връща ORA-00933 съобщение. Решението е да използвате курсори и да върнете изхода в колекция DynamicParameters. Например, докато версията на SQL Server ще изглежда така:

var sql = 
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";

Oracle версията на заявката трябва да изглежда така:

var sql = "BEGIN OPEN :rslt1 FOR SELECT * FROM customers WHERE customerid = :id; " +
                "OPEN :rslt2 FOR SELECT * FROM orders WHERE customerid = :id; " +
                "OPEN :rslt3 FOR SELECT * FROM returns Where customerid = :id; " +
          "END;";

За заявки, изпълнявани срещу SQL Server, Dapper може да се справи от там. Тъй като обаче връщаме резултатите в параметри на курсора, ще трябва да използваме IDynamicParameters колекция за указване на параметри за командата. За да добавите допълнителна бръчка, нормалният DynamicParameters.Add() метод в Dapper използва System.Data.DbType за незадължителния параметър dbType, но параметрите на курсора за заявката трябва да са от тип Oracle.ManagedDataAccess.Client.OracleDbType.RefCursor . За да реша това, използвах решението, което @Daniel Smith предложи в този отговор и създаде персонализирана реализация на IDynamicParameters интерфейс:

    using Dapper;
    using Oracle.ManagedDataAccess.Client;
    using System.Data;
    
    public class OracleDynamicParameters : SqlMapper.IDynamicParameters
    {
        private readonly DynamicParameters dynamicParameters = new DynamicParameters();

        private readonly List<OracleParameter> oracleParameters = new List<OracleParameter>();

        public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction, object value = null, int? size = null)
        {
            OracleParameter oracleParameter;
            if (size.HasValue)
            {
                oracleParameter = new OracleParameter(name, oracleDbType, size.Value, value, direction);
            }
            else
            {
                oracleParameter = new OracleParameter(name, oracleDbType, value, direction);
            }

            oracleParameters.Add(oracleParameter);
        }

        public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction)
        {
            var oracleParameter = new OracleParameter(name, oracleDbType, direction);
            oracleParameters.Add(oracleParameter);
        }

        public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
        {
            ((SqlMapper.IDynamicParameters)dynamicParameters).AddParameters(command, identity);

            var oracleCommand = command as OracleCommand;

            if (oracleCommand != null)
            {
                oracleCommand.Parameters.AddRange(oracleParameters.ToArray());
            }
        }
    }

Така че целият код заедно върви по следния начин:

    using Dapper;
    using Oracle.ManagedDataAccess.Client;
    using System.Data;
    
    int selectedId = 1;
    var sql = "BEGIN OPEN :rslt1 FOR SELECT * FROM customers WHERE customerid = :id; " +
                    "OPEN :rslt2 FOR SELECT * FROM orders WHERE customerid = :id; " +
                    "OPEN :rslt3 FOR SELECT * FROM returns Where customerid = :id; " +
              "END;";
    
    OracleDynamicParameters dynParams = new OracleDynamicParameters();
    dynParams.Add(":rslt1", OracleDbType.RefCursor, ParameterDirection.Output);
    dynParams.Add(":rslt2", OracleDbType.RefCursor, ParameterDirection.Output);
    dynParams.Add(":rslt3", OracleDbType.RefCursor, ParameterDirection.Output);
    dynParams.Add(":id", OracleDbType.Int32, ParameterDirection.Input, selectedId);
    
    using (IDbConnection dbConn = new OracleConnection("<conn string here>"))
    {
        dbConn.Open();
        var multi = dbConn.QueryMultiple(sql, param: dynParams);
        
        var customer = multi.Read<Customer>().Single();
        var orders = multi.Read<Order>().ToList();
        var returns = multi.Read<Return>().ToList();
        ...
        dbConn.Close();
    }


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да получите достъп до базата данни на Oracle през мрежа?

  2. Oracle; ограничаване на редове за стойност на колона

  3. Обработка на часовата зона в уеб приложение

  4. Форматирайте резултатите от заявката в SQL*Plus

  5. Създайте материализиран изглед, който опреснява записите ежедневно