OPはおそらくこの問題を解決してからかなり経ちますが、執筆時点では、この質問の回答は1つだけであり、DapperのQueryMultiple()
を使用する問題は実際には解決されていません。 Oracleを使用したメソッド。 @ Kamolas81が正しく述べているように、公式の例の構文を使用すると、実際にORA-00933: SQL command not properly ended
エラーメッセージ。 QueryMultiple()
の実行方法に関するある種のドキュメントを探していました。 オラクルと一緒でしたが、答えのある場所が実際には1つもなかったことに驚きました。これはかなり一般的な作業だと思いました。 私を救うためにここに答えを投稿しようと思いました :)誰かがこれと同じ問題を抱えている場合に備えて、将来誰かが。
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のメソッドはオプションのdbTypeパラメーターにSystem.Data.DbTypeを使用しますが、クエリのカーソルパラメーターはタイプOracle.ManagedDataAccess.Client.OracleDbType.RefCursor
である必要があります。 。これを解決するために、@DanielSmithが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();
}