sql >> Databáze >  >> RDS >> Oracle

Použití Dapper QueryMultiple v Oracle

Operační program již pravděpodobně tento problém dávno vyřešil, ale v době psaní tohoto článku má tato otázka pouze jednu odpověď a ve skutečnosti neřeší problém použití Dapper's QueryMultiple() metoda s Oracle. Jak @Kamolas81 správně uvádí, použitím syntaxe z oficiálních příkladů skutečně získáme ORA-00933: SQL command not properly ended chybové hlášení. Strávil jsem chvíli hledáním nějaké dokumentace o tom, jak udělat QueryMultiple() s Oracle, ale překvapilo mě, že ve skutečnosti neexistuje jediné místo, které by mělo odpověď. Myslel bych, že je to docela běžný úkol. Myslel jsem, že zde zveřejním odpověď, abych zachránil me :) někdo někdy v budoucnu pro případ, že by měl někdo stejný problém.

Zdá se, že Dapper pouze předává příkaz SQL přímo do ADO.NET a jakéhokoli poskytovatele db, který příkaz provádí. V syntaxi z příkladů, kde je každý příkaz oddělen zalomením řádku, to SQL server bude interpretovat jako více dotazů, které se mají spustit proti databázi, a spustí každý z dotazů a vrátí výsledky do samostatných výstupů. Nejsem odborník na ADO.NET, takže možná pletu terminologii, ale konečným efektem je, že Dapper získá více výstupů dotazů a poté funguje kouzla.

Oracle však nerozpozná vícenásobné dotazy; domnívá se, že příkaz SQL má nesprávný formát a vrací ORA-00933 zpráva. Řešením je použít kurzory a vrátit výstup v kolekci DynamicParameters. Zatímco verze SQL Server by například vypadala takto:

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

verze dotazu Oracle by měla vypadat takto:

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;";

U dotazů spuštěných proti SQL Server to Dapper může zpracovat odtud. Protože však vracíme sady výsledků do parametrů kurzoru, budeme muset použít IDynamicParameters kolekce k zadání parametrů příkazu. Chcete-li přidat další vrásky, normální DynamicParameters.Add() metoda v Dapper používá System.Data.DbType pro volitelný parametr dbType, ale parametry kurzoru pro dotaz musí být typu Oracle.ManagedDataAccess.Client.OracleDbType.RefCursor . K vyřešení tohoto problému jsem použil řešení, které @Daniel Smith navrhl v této odpovědi a vytvořili vlastní implementaci IDynamicParameters rozhraní:

    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());
            }
        }
    }

Takže celý kód dohromady vypadá nějak takto:

    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. Jak zkontrolovat verzi MySQL

  2. Tři výhry výkonu Easy SQL Server

  3. Výběr z databáze na základě seznamu jedinečných párů

  4. MySQL - Jak odstranit z tabulky, když vnořený výběr používá tuto tabulku?