I need to pass an array Object to Oracle 11 DB. I am using annotations based Spring 3.1 and using SimpleJdbcCall to call the procedure on JBOSS server. Here is the relevant jdbcCall.
SimpleJdbcCall call = new SimpleJdbcCall(dataSource)
.withoutProcedureColumnMetaDataAccess()
.withProcedureName(IbeginDataBaseConstants.PROCEDURE_CREATE_NEW_ADMIN.VAL)
.declareParameters(new SqlParameter("inUserEmpID", OracleTypes.INTEGER))
.declareParameters(new SqlParameter("inCountryIDs", OracleTypes.ARRAY, "ibo_number_array" ))
.declareParameters(new SqlParameter("inSysRoleID", OracleTypes.INTEGER))
.declareParameters(new SqlParameter("inLoggedIn", OracleTypes.INTEGER))
.declareParameters(new SqlOutParameter("outStatus", OracleTypes.CHAR))
.declareParameters(new SqlOutParameter("outMsg", OracleTypes.VARCHAR));
As you can see inCountryIDsis an array that I need to send.
With help from google, I was able to get multiple ways through which I can send Array to DB. Here is the first one.
SqlTypeValue value = new AbstractSqlTypeValue() {
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
ArrayDescriptor arrayDescriptor = new ArrayDescriptor(typeName, conn);
ARRAY idArray = new ARRAY(arrayDescriptor, conn, ids);
return idArray;
}
And I added it to parameter source using
sourceMap.addValue("inUserEmpID", newAdmin.getEmpId());
sourceMap.addValue("inCountryIDs", value);
sourceMap.addValue("inSysRoleID", newAdmin.getRoleId());
sourceMap.addValue("inLoggedIn", newAdmin.getLoggedInId());
And the Exception that I got was
org.jboss.jca.adapters.jdbc.jdk6.WrappedConnectionJDK6 cannot be cast to oracle.jdbc.OracleConnection
I understood the reason, SqlTypeValue implemention requires a OracleConnection whereas Spring passes WrappedConnection.
So, I tried to unwrap the connection using WrappedConnection class with this code.
WrappedConnection wrappedConnection = conn.unwrap(WrappedConnection.class);
But here the exception was
Not a wrapper for: org.jboss.jca.adapters.jdbc.WrappedConnection
In another try, I tried to cast existing connection to WrappedConnection using explicit cast with this.
WrappedConnection wrappedConn = (WrappedConnection)conn;
And still no luck.
Exception.
org.jboss.jca.adapters.jdbc.jdk6.WrappedConnectionJDK6 cannot be cast to org.jboss.jca.adapters.jdbc.WrappedConnection
Well, All I had to do is to retrieve the underlying connection, so I tried to cast it into WrappedConnectionJDK6 so that I would be able to call the relevent method there.
WrappedConnectionJDK6 wrappedConnection = (WrappedConnectionJDK6)conn;
leads to
org.jboss.jca.adapters.jdbc.jdk6.WrappedConnectionJDK6 cannot be cast to org.jboss.jca.adapters.jdbc.jdk6.WrappedConnectionJDK6
And the second approach
Map in = Collections.singletonMap("inCountryIDs", new SqlArrayValue(idsArray));
The problem with this approach is that Collections.singletonMap returns an immutable map. So, I can't use it to add more parameters.
Is there any way through which I can retrieve the underlying connection in JBoss Wrapped Connection ? Or is there any other mechanism through which I can pass an array paramter without having to interact with connection ?
Related
I am updating a record on my mongoDb database.
The update is performed in a wrapper for a series of reason, it goes like:
Contact contact = generateContact();
UpdateResult updateResult = performUpdateOne("collection",new Document("field",fieldValue), new Document("$push", new Document("contacts", contact)),updateOptions);
Please keep in mind the new Document("$set", new Document("contacts", contact)) parameter because is the only mongoDb document that contains a reference to a Pojo, this field is used in the the method performUpdateOne
private UpdateResult performUpdateOne(String collectionName, Document filter, Document set, UpdateOptions updateOptions) {
...
...
LOG.debugf("Performing MongoDb UpdateOne command, collection[%s] query[%s] update[%s].", collectionName, filter.toJson(), set.toJson());
UpdateResult updateResult = collection.updateOne(filter, set, updateOptions);
The set.toJson() call gives me the exception:
Exception: : org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class ...Contact. at org.bson.internal.CodecCache.lambda$getOrThrow$1(CodecCache.java:52)
If I comment the LOG:debugf line the collection.updateOne(filter, set, updateOptions) gives me no problem.
Why is the set document serialized correctly in the updateOne method while giving an error when i call .toJson() on it?
Thanks a lot
I am using mongo sync java driver 4.3.4
I'm trying to insert a byte[] into an oracle.sql.BLOB column using spring jdbc 3.0. And I got the following exception:
java.lang.ClassCastException: [B cannot be cast to oracle.sql.BLOB|
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8752)|
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8286)|
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8868)|
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:240)|
at org.apache.commons.dbcp.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:166)|
at org.apache.commons.dbcp.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:166)|
at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:356)|
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:216)|
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:144)|
at org.springframework.jdbc.core.ArgTypePreparedStatementSetter.doSetValue(ArgTypePreparedStatementSetter.java:97)|
at org.springframework.jdbc.core.ArgTypePreparedStatementSetter.setValues(ArgTypePreparedStatementSetter.java:79)|
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:815)|
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:811)|
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:586)|at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:811)|
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:867)|
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:871)|
at org.springframework.jdbc.core.simple.AbstractJdbcInsert.executeInsertInternal(AbstractJdbcInsert.java:366)|
at org.springframework.jdbc.core.simple.AbstractJdbcInsert.doExecute(AbstractJdbcInsert.java:356)|
at org.springframework.jdbc.core.simple.SimpleJdbcInsert.execute(SimpleJdbcInsert.java:118)|
....
The byte[] is being constructed from a ByteBuffer object.
byte[] byte_array = byte_buffer.array();
I tried inserting a java.sql.Blob type as well, but that gave a similar exception:
java.lang.ClassCastException: javax.sql.rowset.serial.SerialBlob cannot be cast to oracle.sql.BLOB|
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8752)|
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8286)|
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8868)|
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:240)|
at org.apache.commons.dbcp.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:166)|
at org.apache.commons.dbcp.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:166)|
at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:356)|
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:216)|
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:144)
....
The java.sql.Blob is also being created from a ByteBuffer object.
Blob blob = new SerialBlob(byte_buffer.array());
It looks like StatementCreatorUtils does not handle java.sql.Blob the way it handles CLOB or NCLOB. Is there a work-around for this? Or is there a different java sql type that I should be using?
Let the type to be BINARY instead of BLOB (Types.BINARY)
I used this way and it's executed successfully
You might want to take a look at Spring's SqlLobValue. Attach your byte[] value to the query parameter map like this:
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("blobParam", new SqlLobValue(byteArrayValue, lobHandler), Types.BLOB);
Where lobHandler is a LobHandler bean (i.e org.springframework.jdbc.support.lob.DefaultLobHandler).
I am creating an ArrayDescriptor in order to pass CLOB data to an Oracle function. I have a class in which I have injected (#Inject) a jdbcTemplate...this is an implementation class which has calls out to Oracle. I am creating the ArrayDescriptor like:
Connection conn = auditJdbcTemplate.getDataSource().getConnection();
ArrayDescriptor keyArryDesc = ArrayDescriptor.createDescriptor("VC_ARR", conn);
The error I am receiving is:
java.lang.ClassCastException: com.sun.proxy.$Proxy183 cannot be cast to oracle.jdbc.OracleConnection
at oracle.sql.ArrayDescriptor.createDescriptor(ArrayDescriptor.java:105
As I stated, I have direct calls in this class to auditJdbcTemplate.update that work successfully so I am not sure why it can't return a valid connection object from the template. I have seen several answers in StackOverflow to get the underlying connection and I have not been able to get that to work.
Maybe someone find it useful:
Connection conn = jdbcTemplate.getDataSource().getConnection().unwrap(OracleConnection.class);
Using LLBLGen 3.1 (Self Servicing) on SQL Server, how would one execute custom SQL, such as:
delete from UserPreference
select * from UserPreference (into a datatable, for example)
Just noticed this question hadn't been answered. With Self Servicing, you'll probably use the TypedListDAO class.
See: Generated code - Fetching DataReaders and projections, SelfServicing
The TypedListDAO class has what you need to do SQL against your database, and it can automatically do projections onto custom classes for you if you need that (see the article).
But basically, (from memory, so might need some slight adjustments), here's what your code might look like:
// inside the DaoClasses namespace of your generated project
TypedListDAO dao = new TypedListDAO();
// do it yourself, and use your project's connection string
string connectionString = CommonDaoBase.ActualConnectionString;
using (var conn = new SqlConnection(connectionString)) { }
// use a DbConnection directly
DbConnection connection = dao.CreateConnection();
// or
connection = dao.DetermineConnectionToUse(null);
DbCommand cmd = connection.CreateCommand();
cmd.CommandText = "SELECT * FROM UserPreferences";
cmd.CommandType = CommandType.Text;
var reader = cmd.ExecuteReader(CommandBehavior.Default);
while (reader.Read()){}
reader.Close();
// use a datareader
IRetrievalQuery query = new RetrievalQuery(
new SqlCommand("SELECT * FROM UserPreferences"));
// or new RetrievalQuery(cmd);
// where you create the cmd using the dao connection
IDataReader reader = dao.GetAsDataReader(null, query,
CommandBehavior.CloseConnection);
while (reader.Read()){}
reader.Close();
// use a datatable - try something like this
// (BUT honestly, you might want to look at the custom projection
// into custom classes capability, or the data reader, instead of this)
DataTable dt = new DataTable();
dao.GetMultiAsDataTable(new EntityFields(0) /* can't be null, i don't think */,
dt, query, null);
// other methods
dao.ExecuteScalarQuery(query, null);
ActionQuery actionQuery = new ActionQuery(new SqlCommand("INSERT ..."));
dao.ExecuteActionQuery(actionQuery, null);
OR, use a micro-orm to do your sql, and just use the connection from the TypedListDAO class above
Some Light-weight micro-orms, like: Dapper (1 cs file), PetaPoco, Massive, etc...
While it is true that you can access the low level data readers, etc.. I think it kind of defeats the purpose of using the ORM. If you just want to fill a datatable from a collection (with or without filtering), you can use the static method GetMultiAsDataTable (which you can pass a predicate expression to if you want to do filtering). If you want to replace more complex SQL (very useful for reporting), check out the dynamic lists capabilities:
http://www.llblgen.com/documentation/4.0/LLBLGen%20Pro%20RTF/hh_start.htm
The QuerySpec is an even nicer way to specify a dynamic query and project it:
http://www.llblgen.com/documentation/4.0/LLBLGen%20Pro%20RTF/hh_start.htm
I am wanting to use the MVCMiniProfiler with Dapper. Is this possible beyond wrapping the "Query" call from dapper in "Using Profiler.Step" block?
I have this basic Dapper call:
Dim comments As List(Of Comment)
Using conn = New SqlConnection(ConnectionString)
conn.Open()
comments = conn.Query(Of Comment)("SELECT * from comments where userid = #userid", New With {.userid= 1})
End Using
The MiniProfiler examples show this
Private Shared _sqlConnection As SqlConnection
Public Shared Function GetOpenConnection() As DbConnection
If _sqlConnection Is Nothing Then
_sqlConnection = New SqlConnection("connection string")
End If
' wrap the connection with a profiling connection that tracks timings
Return MvcMiniProfiler.Data.ProfiledDbConnection.[Get](_sqlConnection, MiniProfiler.Current)
End Function
Where I am stuck is in the implementation of the "Get" on the ProfiledDbConnection. Is it possible to use ProfiledDbConnection while using Dapper?
Good catch, the documentation is out of date, just updated it:
Use something like:
return MiniProfiler.Current != null ?
new MvcMiniProfiler.Data.ProfiledDbConnection(cnn, MiniProfiler.Current) :
cnn;
I killed the factory cause I wanted people to be able to inherit off ProfiledDbConnection and statics can not be virtualized.