【问题标题】:SQL INSERT and SELECT into Oracle using a single command with .NET使用 .NET 的单个命令将 SQL INSERT 和 SELECT 插入 Oracle
【发布时间】:2020-02-12 18:39:19
【问题描述】:

我正在尝试执行在表中插入记录并返回生成主键的 SQL 命令。
我正在使用 .NET Core 3.1 和 Oracle.ManagedDataAccess.Core 包。

这是执行 SQL 命令的 C# 代码(它使用了一些扩展方法,但很清楚它是如何工作的):

        private int PutSomethingInTheDatabase(string entity)
        {
            string sqlComamnd = File.ReadAllText("SQL//Insert Card.sql");

            using (var connection = new Oracle.ManagedDataAccess.Client.OracleConnection(connectionString))
            using (var command = connection.OpenAndUse().CreateTextCommand(sqlComamnd))
            {
                //var reader = command.ExecuteReader();
                //reader.Close();
                //var result = command.ExecuteScalar();
                //return (int)(decimal)result;

                return -1;
            }
        }

理想情况下,我将收到一个值并使用ExecuteScalar() 读取它。
这是一个迭代测试(这就是我从文件中读取 SQL 的原因)。

我要使用的 SQL 应该插入新记录并在同一范围/事务中返回生成的序列,这就是我使用 Begin/End 但我不确定它是正确的方式。
我的问题是我找不到正确的语法来执行最后一个 SELECT 以返回生成的 sequence_id,我也尝试使用 RETURN ...

这是 SQL:

declare new_id number;

BEGIN
    select seq_stage_card.NEXTVAL into new_id from dual;

    INSERT INTO spin_d.stage_card (
        sequence_id,
        field_1,
        field_2
    )
    VALUES (
        new_id,
        'aaa'
        TO_DATE('2003/05/03 21:02:44', 'yyyy/mm/dd hh24:mi:ss')
    );

    select new_id from dual where 1 = 1 ;  -- not valid

END;

-- return new_id ;                   -- not valid 
-- select new_id from dual ;         -- not valid

如何更改 SQL 以返回 new_id ? 还有另一种(更好的)方法可以达到相同的结果吗? 是否安全(隔离范围),或者如果有并发插入,select 会返回错误的 ID?

[更新]
有人建议使用 RETURNING(请参阅此处:Oracle - return newly inserted key value
我已经尝试使用 RETURNRETURNING 但我没有找到任何使用 .NET(或其他框架)驱动程序的真实示例,例如。 OracleSqlCommand 和正确调用执行。
也许它有效,但我仍然无法弄清楚如何使用它。

【问题讨论】:

标签: c# .net oracle


【解决方案1】:

一般情况(当你必须在匿名块中实现一些逻辑,并且returning 不是一个选项时)尝试绑定变量:首先,转@ 查询中的 987654322@ 转换为 :new_id

BEGIN
    SELECT seq_stage_card.NEXTVAL 
      INTO :new_id -- bind variable to return back to c#
      FROM dual;

    INSERT INTO spin_d.Stage_Card (
        sequence_id,
        field_1,
        field_2
    )
    VALUES (
        :new_id,
        'aaa',
         TO_DATE('2003/05/03 21:02:44', 'yyyy/mm/dd hh24:mi:ss')
    );
END;

然后在C#代码中使用:

...
using (var command = connection.OpenAndUse().CreateTextCommand(sqlComamnd))
{
  //TODO: check the syntax and RDBMS type
  command.Parameters.Add(
    ":new_id", 
     OracleDbType.Int32).Direction = ParameterDirection.Output;

  // Execute query 
  command.ExecuteNonQuery();

  // Bind variable reading
  return Convert.ToInt32(command.Parameters[0].Value);
} 

【讨论】:

  • 是的!!! ID(像往常一样)是 Oracle.Decimal,所以我喜欢解析它的方式(因为我讨厌 Convert)是这样的:return (int)(decimal)newidParameter.Value。谢谢。
  • @Alex 75: 口味不同 - 我爱 Convert ;) 如果(何时?)方案更改 Convert 将帮助我(例如,从 string 转换),然后投很可能会崩溃
  • 只是为了帮助下一个人将尝试此代码。正确的演员表是:return (int)(Oracle.ManagedDataAccess.Types.OracleDecimal)(idParameter.Value)。我一直习惯于转换为decimal(使用.Net Framework),也许.Net Core 3.x 的工作方式不同。我也尝试使用 Convert.ToInt32 但我有同样的转换错误:// System.InvalidCastException: 'Unable to cast object of type 'Oracle.ManagedDataAccess.Types.OracleDecimal' to type 'System.IConvertible'.' 再次感谢。
猜你喜欢
  • 1970-01-01
  • 2020-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2015-09-20
相关资源
最近更新 更多