我编写了一个小程序,将一些记录插入到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
等。
答案 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
。您可能还想尝试切换其他字段的类型。