具有ODBC的NHibernate-GenericADOException:无法插入

具有ODBC的NHibernate-GenericADOException:无法插入,nhibernate,odbc,Nhibernate,Odbc,我编写了一个小程序,将一些记录插入oracle数据库。如果我直接连接到oracle,程序运行正常。但是,如果我尝试通过ODBC进行连接,该程序将无法工作。它可以执行SELECT语句,但不能执行INSERT语句 在开发程序时,我在NHibernate配置中使用了以下设置: <property name="connection.provider"> NHibernate.Connection.DriverConnectionProvider </property> &

我编写了一个小程序,将一些记录插入oracle数据库。如果我直接连接到oracle,程序运行正常。但是,如果我尝试通过ODBC进行连接,该程序将无法工作。它可以执行
SELECT
语句,但不能执行
INSERT
语句

在开发程序时,我在NHibernate配置中使用了以下设置:

<property name="connection.provider">
    NHibernate.Connection.DriverConnectionProvider
</property>
<property name="dialect">NHibernate.Dialect.Oracle10gDialect</property>
<property name="connection.connection_string">
    Data Source=192.168.1.43:1521/xxxx;User ID=xxxx;Password=xxxx
</property>
<property name="connection.driver_class">
    NHibernate.Driver.OracleClientDriver
</property>
<property name="hbm2ddl.keywords">auto-quote</property>
内部异常没有附加任何消息

我已经看过了NHibernate生成的SQL。使用开发设置,SQL 为输入生成的结果如下所示:

NHibernate: select STRUCTURE_SEQ.nextval from dual
NHibernate: INSERT INTO STRUCTURE_ASSIGN 
    (CLIENT_ID, STRUCTURE, NAME_CODE, START_DATE, STAT_SEQ) 
    VALUES (:p0, :p1, :p2, :p3, :p4);
    :p0 = 'MAST17' [Type: String (6)],
    :p1 = 'BENEFICIARY' [Type: String (11)],
    :p2 = 27845 [Type: Int64 (0)],
    :p3 = 28/10/2008 00:00:00 [Type: DateTime (0)],
    :p4 = 42830 [Type: Int32 (0)]
NHibernate: select STRUCTURE_SEQ.nextval from dual
NHibernate: INSERT INTO STRUCTURE_ASSIGN 
    (CLIENT_ID, STRUCTURE, NAME_CODE, START_DATE, STAT_SEQ) 
    VALUES (?, ?, ?, ?, ?);
    p0 = 'SCAR03' [Type: String (6)],
    p1 = 'BENEFICIARY' [Type: String (11)],
    p2 = 21525 [Type: Int64 (0)],
    p3 = 07/11/1977 00:00:00[Type: DateTime (0)],
    p4 = 35159 [Type: Int32 (0)]
com.Parameters.AddWithValue("?", (long)1234);
但是,使用生产设置时,生成的SQL如下所示:

NHibernate: select STRUCTURE_SEQ.nextval from dual
NHibernate: INSERT INTO STRUCTURE_ASSIGN 
    (CLIENT_ID, STRUCTURE, NAME_CODE, START_DATE, STAT_SEQ) 
    VALUES (:p0, :p1, :p2, :p3, :p4);
    :p0 = 'MAST17' [Type: String (6)],
    :p1 = 'BENEFICIARY' [Type: String (11)],
    :p2 = 27845 [Type: Int64 (0)],
    :p3 = 28/10/2008 00:00:00 [Type: DateTime (0)],
    :p4 = 42830 [Type: Int32 (0)]
NHibernate: select STRUCTURE_SEQ.nextval from dual
NHibernate: INSERT INTO STRUCTURE_ASSIGN 
    (CLIENT_ID, STRUCTURE, NAME_CODE, START_DATE, STAT_SEQ) 
    VALUES (?, ?, ?, ?, ?);
    p0 = 'SCAR03' [Type: String (6)],
    p1 = 'BENEFICIARY' [Type: String (11)],
    p2 = 21525 [Type: Int64 (0)],
    p3 = 07/11/1977 00:00:00[Type: DateTime (0)],
    p4 = 35159 [Type: Int32 (0)]
com.Parameters.AddWithValue("?", (long)1234);
代码中的其他内容没有改变-只有配置文件

有人知道这里出了什么问题吗?我怀疑是使用序列来生成表的ID(STAT_SEQ列),或者是导致第二组SQL中的参数是
,而不是
p0
p1
等。NHibernate使用位置参数。通过查看
DriverBase
可以看出,即使它在SQL语句中使用了“?”,NHibernate也会命名参数p0、p1、p2等。。。不幸的是,Oracle ODBC驱动程序不喜欢这样,这可以从对的响应中看出

解决您的问题的最简单的方法是创建一个自定义方言,该方言基于但带有我在下面包含的更改。此方言将生成名称为空字符串的参数,这是Oracle ODBC驱动程序所需的格式

请注意,我不是100%确定这是正确的格式,我已经看到一些示例,其中参数名称的格式为0、?1、?2等。。。但如果是这种情况,您可以修改
ToParameterName
以返回
StringHelper.SqlParameter+index

另外请注意,您不能仅从
DriverBase
继承并重写必要的属性,因为所需的更改之一是静态属性

我还建议在上创建一个记录单,因为这种行为肯定是一个bug

public class OracleOdbcDriver : IDriver, ISqlParameterFormatter
{
  ....
  public bool UseNamedPrefixInSql
  {
    get { return false; }
  }

  public bool UseNamedPrefixInParameter
  {
    get { return false; }
  }

  public string NamedPrefix
  {
    get { return string.Empty; }
  }
  ....
  private static string ToParameterName(int index)
  {
    return String.Empty;
  }
  ....
}

哇,这确实是一个很难确定的问题

据我所知,错误在这一行:

p2 = 21525 [Type: Int64 (0)],
特别是,如果我将
NameCode
的类型更改为
int
而不是
long
,则插入成功。不知何故,ODBC在64位整数上遇到了障碍。它中断时也没有任何类型的描述性错误消息,这非常令人沮丧。由于此问题仅在使用ODBC时出现,而不是在运行正常的
OracleClientDriver
时出现,因此它一定是ODBC中的错误,而不是我的数据库配置问题

我还尝试直接使用ODBC:

var queryString = "insert into STRUCTURE_ASSIGN (CLIENT_ID, \"STRUCTURE\", NAME_CODE, STAT_SEQ, "
    + "START_DATE, FINISH_DATE, MEMO_NUMBER, ALTERNATE, ALTERNATE_NAME_CODE, ADMIN_NAME, "
    + "AUDIT_NAME, VALID_DATE, AUDIT_ACTION, DIRECTOR_CLASS) "
    + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?);";

using (var odbcConnection = new OdbcConnection(connectionString))
{
    OdbcCommand com = new OdbcCommand(queryString, odbcConnection);

    com.Parameters.AddWithValue("?", "aaa");
    com.Parameters.AddWithValue("?", "aaa");
    com.Parameters.AddWithValue("?", 1234);
    com.Parameters.AddWithValue("?", 100000);

    com.Parameters.AddWithValue("?", DateTime.Now);
    com.Parameters.AddWithValue("?", DateTime.Now);
    com.Parameters.AddWithValue("?", 1234);
    com.Parameters.AddWithValue("?", 'N');
    com.Parameters.AddWithValue("?", 1234);
    com.Parameters.AddWithValue("?", "TRUST");

    com.Parameters.AddWithValue("?", "TRUST");
    com.Parameters.AddWithValue("?", DateTime.Now);
    com.Parameters.AddWithValue("?", 'C');
    com.Parameters.AddWithValue("?", 'A');

    odbcConnection.Open();
    var rd = com.ExecuteNonQuery();
    odbcConnection.Close();
}
上述代码有效。但是,如果您像这样更改其中一行:

NHibernate: select STRUCTURE_SEQ.nextval from dual
NHibernate: INSERT INTO STRUCTURE_ASSIGN 
    (CLIENT_ID, STRUCTURE, NAME_CODE, START_DATE, STAT_SEQ) 
    VALUES (:p0, :p1, :p2, :p3, :p4);
    :p0 = 'MAST17' [Type: String (6)],
    :p1 = 'BENEFICIARY' [Type: String (11)],
    :p2 = 27845 [Type: Int64 (0)],
    :p3 = 28/10/2008 00:00:00 [Type: DateTime (0)],
    :p4 = 42830 [Type: Int32 (0)]
NHibernate: select STRUCTURE_SEQ.nextval from dual
NHibernate: INSERT INTO STRUCTURE_ASSIGN 
    (CLIENT_ID, STRUCTURE, NAME_CODE, START_DATE, STAT_SEQ) 
    VALUES (?, ?, ?, ?, ?);
    p0 = 'SCAR03' [Type: String (6)],
    p1 = 'BENEFICIARY' [Type: String (11)],
    p2 = 21525 [Type: Int64 (0)],
    p3 = 07/11/1977 00:00:00[Type: DateTime (0)],
    p4 = 35159 [Type: Int32 (0)]
com.Parameters.AddWithValue("?", (long)1234);
ODBC抛出与NHibernate包装相同的无用错误消息,因此这在NHibernate中不是错误

总结
如果遇到类似问题,请尝试将任何
long
变量更改为
int
。您可能还想尝试切换其他字段的类型。

您究竟为什么要将ODBC与具有受支持的本机驱动程序的数据库一起使用?@DiegoMijelshon他们都在客户端通过ODBC运行。我们尝试使用本机驱动程序,但无法在他们的站点上运行。我们不能在他们的系统上做太多的修改,所以我们可以更容易地让程序像他们现有的东西一样通过ODBC运行。非常感谢您的帮助。我没想到要换司机!我将研究并制定出使用的确切格式。我花了几个小时尝试使用各种不同的参数名称,但不幸的是,似乎没有一个有效。我可能不得不暂时搁置它,尝试另一种方法。