OP har sandsynligvis for længst løst problemet nu, men i skrivende stund har dette spørgsmål kun ét svar, og det løser ikke rigtig problemet med at bruge Dappers QueryMultiple()
metode med Oracle. Som @Kamolas81 korrekt angiver, ved at bruge syntaksen fra de officielle eksempler, vil man faktisk få ORA-00933: SQL command not properly ended
fejl besked. Jeg brugte et stykke tid på at søge efter en form for dokumentation om, hvordan man gør QueryMultiple()
med Oracle, men jeg var overrasket over, at der ikke rigtig var ét sted, der havde et svar. Jeg ville have troet, at det var en ret almindelig opgave. Jeg tænkte, at jeg ville sende et svar her for at redde mig :) nogen engang i fremtiden bare hvis nogen skulle have det samme problem.
Dapper ser ud til at sende SQL-kommandoen direkte videre til ADO.NET og hvilken som helst db-udbyder, der udfører kommandoen. I syntaksen fra eksemplerne, hvor hver kommando er adskilt af et linjeskift, vil SQL-serveren fortolke det som flere forespørgsler, der skal køres mod databasen, og den vil køre hver af forespørgslerne og returnere resultaterne til separate output. Jeg er ikke en ADO.NET-ekspert, så det kan være, at jeg roder terminologien ud, men sluteffekten er, at Dapper får de mange forespørgselsudgange og derefter udfører sin magi.
Oracle genkender dog ikke de mange forespørgsler; den mener, at SQL-kommandoen er forkert udformet og returnerer ORA-00933
besked. Løsningen er at bruge markører og returnere output i en DynamicParameters-samling. For eksempel, mens SQL Server-versionen ville se sådan ud:
var sql =
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";
Oracle-versionen af forespørgslen skal se sådan ud:
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;";
For forespørgsler, der køres mod SQL Server, kan Dapper håndtere det derfra. Men fordi vi returnerer resultatsættene til markørparametre, bliver vi nødt til at bruge en IDynamicParameters
samling for at angive parametre for kommandoen. For at tilføje en ekstra rynke skal du bruge den normale DynamicParameters.Add()
metode i Dapper bruger en System.Data.DbType til den valgfri dbType parameter, men markørparametrene for forespørgslen skal være af typen Oracle.ManagedDataAccess.Client.OracleDbType.RefCursor
. For at løse dette brugte jeg den løsning, som @Daniel Smith foreslog i dette svar
og oprettet en tilpasset implementering af IDynamicParameters
grænseflade:
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());
}
}
}
Så al koden sammen lyder sådan her:
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();
}