简体   繁体   English

Oracle存储过程可与ADO.NET一起使用,但与OrmLite一起抛出异常?

[英]Oracle stored procedure works with ADO.NET but with OrmLite throws exception?

I have a following stored procedure: 我有以下存储过程:

create or replace PROCEDURE PRODUCT_DETAILS(p_code IN VARCHAR2, 
                                            cursorParam OUT SYS_REFCURSOR)
IS
BEGIN
  OPEN cursorParam FOR
  select str_auth_code, str_name
  from strs
  where str_auth_code = p_code;
END;

How can I call it with OrmLite? 如何用OrmLite来称呼它? I've tryied: 我试过了:

connection.SqlList<Product>(@"EXEC PRODUCT_DETAILS @p_code", new { p_code = code });

but it throws an exception ORA-01036: illegal variable name/number 但它引发异常ORA-01036: illegal variable name/number

I just tried to do it with plain old ADO.NET and it worked: 我只是尝试使用普通的旧ADO.NET来做到这一点,并且效果很好:

using (var conn = new OracleConnection(connectionString))
{
    OracleCommand cmd = new OracleCommand();
    cmd.Connection = conn;
    cmd.CommandText = "PRODUCT_DETAILS";
    cmd.CommandType = CommandType.StoredProcedure;

    cmd.Parameters.Add("p_code", OracleType.NVarChar).Value = redemptionCode;
    cmd.Parameters.Add("cursorParam", OracleType.Cursor);
    cmd.Parameters["cursorParam"].Direction = ParameterDirection.Output;

    conn.Open();
    OracleDataReader dr = cmd.ExecuteReader();

    while (dr.Read())
    {
        Console.WriteLine(dr["Name"]);

    }
    conn.Close();
}

But I can't figure out how to do the same task with OrmLite. 但我不知道如何使用OrmLite执行相同的任务。

What you have looks good. 你所拥有的看起来不错。 If you were concerned about the verbosity of the code, and were using a number of stored procedures, then you could use this extension method to remove some of the repeated code: 如果您担心代码的冗长性,并且正在使用许多存储过程,则可以使用此扩展方法删除一些重复的代码:

Extension Method: 扩展方式:

public static class StoredProcExtensions
{
    public static List<T> ExecStoredProcedure<T>(this IDbConnection connection, string procedureName, object parameters = null, string outputCursor = "cursorParam")
    {
        return connection.Exec(c => {
            c.CommandText = procedureName;
            c.CommandType = CommandType.StoredProcedure;

            // Create the parameters from the parameters object
            if(parameters != null)
                foreach(var property in parameters.GetType().GetPublicProperties())
                    c.Parameters.Add(new OracleParameter(property.Name, property.GetValue(parameters)));

            // Add the output cursor
            if(outputCursor != null)
                c.Parameters.Add(new OracleParameter(outputCursor, OracleDbType.RefCursor) { Direction = ParameterDirection.Output });

            // Return the result list
            return c.ExecuteReader().ConvertToList<T>();
        });
    }
}

Usage: 用法:

var download = connection.ExecStoredProcedure<ProductDownloads>(
                   "PRODUCT_DETAILS", 
                   new { p_code = redemptionCode }
               );

foreach (var productDownload in download)
{
    Console.WriteLine(productDownload.Name);
}

So the arguments are: 因此参数为:

  1. Stored procedure name ie PRODUCT_DETAILS 存储过程名称, PRODUCT_DETAILS

  2. Optional An object of input parameters 可选输入参数的对象
    ie new { p_code = redemptionCode, other = "value" } new { p_code = redemptionCode, other = "value" }

  3. Optional The name of the output cursor - defaults to cursorParam 可选输出游标的名称-默认为cursorParam

Note: this code is untested, because I don't have Oracle setup, but it does compile, and hopefully goes some way to simplifying your stored procedures. 注意:此代码未经测试,因为我没有安装Oracle,但确实可以编译,因此希望可以通过某种方式简化存储过程。

So far ended up with following code: 到目前为止,结果如下:

using (var connection = factory.Open())
{
    var download = 
         connection.Exec(c =>
          {
               c.CommandText = "PRODUCT_DETAILS";
               c.CommandType = CommandType.StoredProcedure;
               c.Parameters.Add(
                  new Oracle.DataAccess.Client.OracleParameter("p_code", Oracle.DataAccess.Client.OracleDbType.NVarchar2) { Value = redemptionCode });
               c.Parameters.Add(
                   new Oracle.DataAccess.Client.OracleParameter("cursorParam", Oracle.DataAccess.Client.OracleDbType.RefCursor) { Direction = ParameterDirection.Output });
                return c.ExecuteReader().ConvertToList<ProductDownloads>();
           });

           foreach (var productDownload in download)
           {
               Console.WriteLine(productDownload.Name);
           }
}

But I think there should be a better way for doing this. 但是我认为应该有一个更好的方法。

Late to the party, but this problem can be solved by simply adding BEGIN and END to the statement... it will work. 聚会晚了,但是可以通过在语句中添加BEGINEND来解决此问题……它将起作用。

In my case, I was trying to refresh a materialized view, only after adding BEGIN and END will it work, otherwise it will throw OracleException ORA-00900: invalid SQL statement... 就我而言,我试图刷新实例化视图,只有在添加BEGIN和END之后它才能起作用,否则它将抛出OracleException ORA-00900: invalid SQL statement...

This should work: 这应该工作:

db.ExecuteSql("BEGIN DBMS_SNAPSHOT.REFRESH('" + materializedViewName + "'); END;");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM