C#中的OracleCommand类型Text不接受子查询中的参数

oknrviil  于 2023-04-20  发布在  Oracle
关注(0)|答案(1)|浏览(157)

这段代码不起作用:

using (var conn = new OracleConnection(ConnString))
{
    conn.Open();
    using (var t = conn.BeginTransaction())
    {
        var sanitizer = new HtmlSanitizer();

        var sqlWithSubquery = @"INSERT INTO owner.dummy_table (idDog, idCat, idBunny) VALUES (
            SequenceDogs.nextval, 
            :Parameter_IdCat, 
            (SELECT idBunny FROM owner.bunny_table WHERE
            IdTree = :Parameter_IdTree))";

        var cmdInsertWithSubquery = new OracleCommand(sqlWithSubquery.ToString(), conn);
        cmdInsertWithSubquery.Parameters.Add(new OracleParameter("Parameter_IdCat", OracleDbType.Int32)).Value = sanitizer.Sanitize(idCat);
        cmdInsertWithSubquery.Parameters.Add(new OracleParameter("Parameter_IdTree", OracleDbType.Int32)).Value = sanitizer.Sanitize(idTree);
        cmdInsertWithSubquery.CommandType = System.Data.CommandType.Text;

        var result = cmdInsertWithSubquery.ExecuteNonQueryAsync();
        if (result.Status == TaskStatus.Faulted)
        {
            sbLog.AppendLine(result.Exception.InnerException.Message.ToString());
        }
        else
        {
            sbLog.AppendLine("Success");
        }

        t.Commit();

        conn.Close();
    }
}

它会导致错误:ORA-01400:无法将NULL插入(“owner”.“dummy_table”.“idBunny”)
而下面的工作刚刚好:

using (var conn = new OracleConnection(ConnString))
{
    conn.Open();
    using (var t = conn.BeginTransaction())
    {
        var sanitizer = new HtmlSanitizer();

        // Doing the subquery apart, because for some reason it won't work inside an INSERT
        var sqlSubquery = @"SELECT idBunny FROM owner.bunny_table WHERE
            IdTree = :Parameter_IdTree";
        var cmdSubquery = new OracleCommand(sqlSubquery.ToString(), conn);
        cmdSubquery.Parameters.Add(new OracleParameter("Parameter_IdTree", OracleDbType.Int32)).Value = sanitizer.Sanitize(idTree);
        cmdSubquery.CommandType = System.Data.CommandType.Text;
        var idBunny = cmdSubquery.ExecuteScalar();


        var sqlInsert = @"INSERT INTO owner.dummy_table (idDog, idCat, idBunny) VALUES (
            SequenceDogs.nextval, 
            :Parameter_IdCat, 
            :Parameter_IdBunny)";
        var cmdInsert = new OracleCommand(sqlInsert.ToString(), conn);
        cmdInsert.Parameters.Add(new OracleParameter("Parameter_IdCat", OracleDbType.Int32)).Value = sanitizer.Sanitize(idCat);
        cmdInsert.Parameters.Add(new OracleParameter("Parameter_IdBunny", OracleDbType.Int32)).Value = sanitizer.Sanitize(idBunny.ToString());
        cmdInsert.CommandType = System.Data.CommandType.Text;

        var result = cmdInsert.ExecuteNonQueryAsync();
        if (result.Status == TaskStatus.Faulted)
        {
            sbLog.AppendLine(result.Exception.InnerException.Message.ToString());
        }
        else
        {
            sbLog.AppendLine("Success");
        }

        t.Commit();

        conn.Close();
    }
}

问题解决了,但它看起来像一个丑陋的解决方案,我想知道为什么第一种方法是无效的。
是绑定过程中的一些bug还是设计的一个特性?

kgqe7b3p

kgqe7b3p1#

就我从这篇文章(Oracle identity column and insert into select)中所能收集到的信息而言,一个变通方案可能是

INSERT INTO owner.dummy_table (idDog, idCat, idBunny) 
 SELECT * FROM (
   SELECT SequenceDogs.nextval, :Parameter_IdCat, bt.idBunny
     FROM owner.bunny_table bt
    WHERE bt.IdTree = :Parameter_IdTree);

它还没有经过测试,但可能会让你找到解决方案。正如已经指出的,确保idBunny不会导致NULL值(在WHERE子句中添加 idBunny IS NOT NULL 以确保安全)。

相关问题