在Oracle中使用Dapper QueryMultiple

Kam*_*s81 15 oracle dapper

我正在尝试使用dapper与Oracle(ODP.NET),我想使用"QueryMultiple"功能.

将此字符串传递给QueryMultiple方法:

 var query = "Select CUST_ID CustId from Customer_info WHERE CUST_ID=:custId;" +
                   "Select CUST_ID CustId from BCR WHERE CUST_ID=:custId";
Run Code Online (Sandbox Code Playgroud)

我收到一个ORA-00911:无效的字符错误

有没有办法做到这一点或不可能?

TKS

gre*_*l96 27

OP可能很久以来就已经解决了这个问题,但截至撰写本文时,这个问题只有一个答案,并没有真正解决使用Dapper QueryMultiple()方法与Oracle的问题.正如@ Kamolas81正确地指出的那样,通过使用官方示例中的语法,确实会得到ORA-00933: SQL command not properly ended错误消息.我花了一些时间搜索关于如何QueryMultiple()使用Oracle的某些文档,但我很惊讶没有一个地方有答案.我本以为这是一项相当普遍的任务.我以为我会在这里发布一个答案来救 :)以后的某个时候,以防任何人碰巧遇到同样的问题.

Dapper似乎只是将SQL命令直接传递给ADO.NET以及任何数据库提供程序正在执行命令.在示例的语法中,每个命令由换行符分隔,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";
Run Code Online (Sandbox Code Playgroud)

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;";
Run Code Online (Sandbox Code Playgroud)

对于针对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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以所有的代码都是这样的:

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案.或者,"除非你喜欢痛苦,否则不要使用Oracle." :) (14认同)

Ben*_*Ben 0

我怀疑这是两三个不同的事情:

  1. 您的第一个查询不应包含分号
  2. 查询之间没有换行符
  3. 使用说明暗示绑定字符不是@:不知道这是否取决于所使用的 RDBMS)。

如果您查看Dapper Google 代码页面,给出的示例QueryMultiple()是:

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

using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
   var customer = multi.Read<Customer>().Single();
   var orders = multi.Read<Order>().ToList();
   var returns = multi.Read<Return>().ToList();
   ...
} 
Run Code Online (Sandbox Code Playgroud)

删除分号;添加新行,如果仍有问题,请更改绑定字符。