NHibernate与ODBC - GenericADOException:无法插入

时间:2013-04-26 15:55:02

标签: nhibernate odbc

我编写了一个小程序,将一些记录插入到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>

通过这些设置,程序可以正常工作。

对于制作,我使用这些设置:

<property name="connection.provider">
    NHibernate.Connection.DriverConnectionProvider
</property>
<property name="dialect">NHibernate.Dialect.Oracle10gDialect</property>
<property name="connection.connection_string">
    DSN=TRUST;Server=oracle;UID=xxxx;PWD=xxxx
</property>
<property name="connection.driver_class">
    NHibernate.Driver.OdbcDriver
</property>
<property name="hbm2ddl.keywords">auto-quote</property>

使用生产设置,当我尝试插入数据时出现此异常:

NHibernate.Exceptions.GenericADOException: could not insert: [Domain.Phoenix.StructureAssign#35159][SQL: INSERT INTO STRUCTURE_ASSIGN (CLIENT_ID, STRUCTURE, NAME_CODE, START_DATE, FINISH_DATE, MEMO_NUMBER, ALTERNATE, ALTERNATE_NAME_CODE, ADMIN_NAME, AUDIT_NAME, VALID_DATE, AUDIT_ACTION, DIRECTOR_CLASS, STAT_SEQ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)] ---> System.Data.Odbc.OdbcException
   at System.Data.Odbc.OdbcConnection.HandleError(OdbcHandle hrHandle, RetCode retcode)
   at System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, String method, Boolean needReader, Object[] methodArguments, SQL_API odbcApiMethod)
   at System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, String method, Boolean needReader)
   at System.Data.Odbc.OdbcCommand.ExecuteNonQuery()
   at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd)
   at NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation)
   at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Boolean[] notNull, Int32 j, SqlCommandInfo sql, Object obj, ISessionImplementor session)
   --- End of inner exception stack trace ---
   at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Boolean[] notNull, Int32 j, SqlCommandInfo sql, Object obj, ISessionImplementor session)
   at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Object obj, ISessionImplementor session)
   at NHibernate.Impl.StatelessSessionImpl.Insert(String entityName, Object entity)
   at NHibernate.Impl.StatelessSessionImpl.Insert(Object entity)
   at Domain.Repositories.StatelessRepository.Add[T](T model) in c:\Users\Owner\Dev\\Domain\Repositories\StatelessRepository.cs:line 112
   at PatchImport.Program.InsertBeneficiaries() in c:\Users\Owner\Dev\PatchImport\Program.cs:line 232
   at PatchImport.Program.Main(String[] args) in c:\Users\Owner\Dev\PatchImport\Program.cs:line 60

内部异常没有附加消息。

我看过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)]

但是,对于生产设置,生成的SQL如下所示:

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)]

代码中没有其他内容发生了变化 - 只有配置文件。

有谁知道这里出了什么问题?我怀疑它是使用序列来生成表的ID(STAT_SEQ列),还是导致第二组SQL中的参数为?而不是{{ 1}},p0等。

2 个答案:

答案 0 :(得分:1)

NHibernate OdbcDriver使用位置参数。从DriverBase看,你可以看到即使它正在使用“?”在SQL语句中,NHibernate将参数命名为p0,p1,p2等...不幸的是,Oracle ODBC驱动程序不喜欢这一点,因为可以从对this question的响应中得到证明。

解决问题的最简单方法是根据DriverBase创建自定义方言,但我在下面提供了更改。此方言将生成带有名称空字符串的参数,其中my research是Oracle ODBC驱动程序所需的格式。

请注意,我不是100%确定这是正确的格式,我已经看到一些参数名称被格式化的示例?0,?1,?2等...但是如果这是您只需修改ToParameterName即可返回StringHelper.SqlParameter + index

另请注意,您不能仅继承{​​{1}}并覆盖必要的属性,因为其中一项必需的更改是静态属性。

我还建议在JIRA上创建一张票,因为这种行为绝对是个错误。

DriverBase

答案 1 :(得分:0)

哇,这肯定很难确定。

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

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();
}

以上代码有效。但是,如果您更改其中一行,请执行以下操作:

com.Parameters.AddWithValue("?", (long)1234);

ODBC会抛出与NHibernate包装相同的无用错误消息,因此这不是NHibernate中的错误。

摘要

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

相关问题