De OP heeft het probleem waarschijnlijk al lang opgelost, maar op het moment van schrijven heeft deze vraag maar één antwoord en lost het niet echt het probleem op van het gebruik van Dapper's QueryMultiple()
methode met Oracle. Zoals @Kamolas81 correct aangeeft, zal men inderdaad de ORA-00933: SQL command not properly ended
krijgen door de syntaxis uit de officiële voorbeelden te gebruiken. foutmelding. Ik heb een tijdje gezocht naar een soort documentatie over hoe je QueryMultiple()
. moet doen met Oracle, maar ik was verrast dat er niet echt één plek was die een antwoord had. Ik had gedacht dat dit een vrij algemene taak was. Ik dacht dat ik hier een antwoord zou plaatsen om mij te redden :) iemand in de toekomst voor het geval iemand toevallig hetzelfde probleem heeft.
Dapper lijkt de SQL-opdracht gewoon rechtstreeks door te geven aan ADO.NET en welke db-provider de opdracht ook uitvoert. In de syntaxis van de voorbeelden, waarbij elke opdracht wordt gescheiden door een regeleinde, interpreteert SQL-server dat als meerdere query's die op de database moeten worden uitgevoerd en voert elke query uit en retourneert de resultaten in afzonderlijke uitvoer. Ik ben geen ADO.NET-expert, dus ik verpruts misschien de terminologie, maar het eindresultaat is dat Dapper de meerdere query-uitvoer krijgt en vervolgens zijn magie doet.
Oracle herkent de meervoudige zoekopdrachten echter niet; het denkt dat het SQL-commando verkeerd is opgemaakt en retourneert de ORA-00933
bericht. De oplossing is om cursors te gebruiken en de uitvoer terug te sturen in een DynamicParameters-verzameling. Terwijl de SQL Server-versie er bijvoorbeeld als volgt uit zou zien:
var sql =
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";
de Oracle-versie van de query zou er als volgt uit moeten zien:
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;";
Voor query's die tegen SQL Server worden uitgevoerd, kan Dapper het vanaf daar afhandelen. Omdat we de resultaatsets echter teruggeven in cursorparameters, moeten we een IDynamicParameters
gebruiken collection om parameters voor de opdracht op te geven. Om een extra rimpel toe te voegen, de normale DynamicParameters.Add()
methode in Dapper gebruikt een System.Data.DbType voor de optionele parameter dbType, maar de cursorparameters voor de query moeten van het type Oracle.ManagedDataAccess.Client.OracleDbType.RefCursor
zijn . Om dit op te lossen heb ik de oplossing gebruikt die @Daniel Smith heeft voorgesteld in dit antwoord
en creëerde een aangepaste implementatie van de IDynamicParameters
interface:
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());
}
}
}
Dus alle code samen gaat ongeveer als volgt:
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();
}