As i mentioned at the mail subject, i am having problem with not mutable map inside BasicDynaBean.
As far as i know, it is the default behaviour of this map.
What i would like to do is, simply retrieve the resultset from db which will create a list including DynaBeans.
For viewing the database table, everything works fine, the problem occurs when i try to edit it and i get the following exception:
Caused by: javax.el.PropertyNotWritableException
at javax.el.MapELResolver.setValue(MapELResolver.java:267)
at com.sun.faces.el.DemuxCompositeELResolver._setValue(DemuxCompositeELResolver.java:255)
at com.sun.faces.el.DemuxCompositeELResolver.setValue(DemuxCompositeELResolver.java:281)
at com.sun.el.parser.AstValue.setValue(AstValue.java:201)
at com.sun.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:291)
at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:131)
... 50 more
I assume, this is because of the map inside dyna bean is not mutable.
I think one option is to change the default behaviour of the map by editing the source code of BeanUtils library.
On the other hand, i think the implementors of this library must have thought this functionality somehow...
Below is the code snippet that i use for retrieving the result set as DynaBeans.
String query = "SELECT * FROM test.a";
Statement stmt = (Statement) con.createStatement();
ResultSet rs = stmt.executeQuery(query);
RowSetDynaClass rsdc = new RowSetDynaClass(rs);
rs.close();
stmt.close();
dynaObjectList= rsdc.getRows();
I tried to use LazyDynaMap as well, editing the table worked fine but the
Map didnt allow me to put multiple data since the key is not unique for other datasets.
Because the key is the property name.
I would be really appreciated if you suggest me hints.
Thanks in advance.
I am really looking forward to see the answers if possible.
Best regards.
Ercan CANLIER
By default, BasicDynaBean has mutable map for the DynaBeans. I created another map which is immutable by LazyDynaMap and solved the problem. Hope this helps for someone else.
setDecoratedDynaObjectList(rsdc.getRows());
Iterator<DynaBean> it=decoratedDynaObjectList.iterator();
while(it.hasNext()){
BasicDynaBean dynaBean = (BasicDynaBean) it.next();
Map<String,Object> modifiableMap=new DynaBeanPropertyMapDecorator(dynaBean, false);
DynaBean mutableDynaBean=new LazyDynaMap(modifiableMap);
modifiableDynaObjectList.add(mutableDynaBean);
}
Related
Before I explain my problem I would like to say that I know the basics of JDBC but not really used to it.
I am using an updatable result set to hold data from 2 different tables, as in the following sample code:
searchQry = "SELECT ct.CustomerName, ct.Email, ct.PhoneNo, ot.ItemName
FROM CUSTOMER_TABLE ct JOIN ORDER_Table ot
ON ct.OrderID = ot.OrderID";
prestmt = dbcon.prepareStatement(searchQry, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
uprs = prestmt.executeQuery();
uprs.updateLong("ut.PhoneNo", 7240987456L);
uprs.updateString("otItemName", "GTA5");
uprs.updateRow();
I would like to know if I will update the database from somewhere else (not using the same result set object) while the result set, upsr, connected to the database, whether uprs will get updated with it or it will throw an error or it will go with the old data itself. Sorry if it a newbie question but I can't really test that on my DB without knowing the outcomes and safe measures.
Please, suggest me if there is any better way to update the underlining db along with the data in the ResultSet without having any transaction issues when changing from different places.
Using:
Oracle Database for JDBC connection.
The code that I am working with primarily uses Spring and jdbcTemplate as a way to query the database.
As a non-working example, but just to get the idea across of how I get data and display it on my website...
There will be some object called Bike.
List<bikeObject> bikes = new ArrayList<>();
List<Map<String, Object>> rows = jdbcTemplate.queryForList(bikeQuery));
for (Map<String<Object> row : rows){
bikeObject b = new bikeObject();
b.setProperty((String row.get(-property-));
....
bikes.push(bikeObject)
}
However, sometimes the query can be too large and my computer can run out of memory or the database query can timeout.
A solution that was brought to my attention was to just query it into a ResultSet and then iterate through and stream it directly to a file. I can scrap the display on the website and just let the user download an excel table on a click of a button.
I see that I can use something like (copied from the oracle site)
OracleDataSource ods = new OracleDataSource();
ods.setURL(url);
ods.setUser(user);
ods.setPassword(password);
String URL = "jdbc:oracle:thin:scott/tiger#//myhost:1521/orcl");
ods.setURL(URL);
Connection conn = ods.getConnection();
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery(query);
from here I think I can just iterate through rset and write to a file using BufferedWriter.
The issue I have with this is that my code is pretty consistent so how would I set the URL/User/Password from the Spring properties file that I have? I don't want to type it in the file on a one time occasion.
Also, is this the best way to approach this problem? Can I write to file using jdbcTemplate + ResultSet? I'm stuck on finding a way how.
Slight update:
I assume that the query (passed off from someone else) is optimal and that all the data is necessary. This leaves me with the conclusion of streaming the query results straight to file. Is there a way I can do this with jdbcTemplate or do I have to do it via
Connection conn = ods.getConnection();
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery(swSb);
And iterating through it on a next() basis?
You don't describe well the problem: Do you really need all data? is database setup with indexes and is the query optimal?
You can use oracle pagination support http://www.oracle.com/technetwork/issue-archive/2007/07-jan/o17asktom-093877.html so the user get first X elements.
If you really need all data and it is a lot I would avoid mapping to an object specially object instantiation inside a loop.
It would help if you could tell how many rows are you expecting
I have been using open source data set provider Casper to achieve in-memory representation of a collection of Database objects in Java.
Github Repository : https://github.com/casperds/casperdatasets
Below is the code that I have been using to pull data in Casper datasets
String[] primaryKeys = { "QUESTION_ID" };
if (resultSet != null)
{
container = CDataCacheDBAdapter.loadData(resultSet, null, primaryKeys,new HashMap<Object, Object>());
lCDataRowset = container.getAll();
preparedStatement.close();
resultSet.close();
}
The problem with using this is, when I don't mention primary keys then DBAdapter does not load data. And If I mention some column as primary keys then "Order By" does not have effect in the dataset. It just orders by primary keys.
I want to be able to pull data in dataset in order the way I have mentioned in the query.
Did anybody face this issue? Any kind of help is appreciated!! Thanks
Well it turned out to be very stupid issue. If you pass null for primaryKeys parameter then it returns data in the order the way it returns in MySQL query browser.
I thought this could help someone someday. That's why keeping this post other wise I would have deleted it.
I have a problem - I create my SQL queries dynamically and basing on user input options. So the user has 5 parameters (actually it's more) and he can choose to use some of them (all if he wants) or none and specify their value in the query. So I construct my query String (basic the WHERE conditions) by checking if a parameter was selected and if a value was provided. However now there is the problem of special characters like '. I could try to use replaceAll("'", "\\") but this is quite dull and I know that preparedStatement.setString() does the job better. However for me I would need than to check again if the parameter was provided and if the previous one were also (to specify the poison of ? and connect it to the right parameter). This causes a lot of combinations and does not look elegant.
So my question is - can I somehow receive the string preparedStatement.setString() produces? Or is there a similar function that would do the same job and give me the String so I can put it in the query manually.
Maybe the intro was too long but someone might have a better idea and I wanted to explain why I need it.
What you can do is construct the basic, unparameterized SQL query based on whether the parameters were specified, and then use the prepared statement to fill in the parameters.
It could look something like this (rough sketch):
Map<String, Object> parameterValues = /*from user*/;
List<String> parameterNames = Arrays.asList("field1", "field2", "field3");
List<Object> valueList = new ArrayList<Object>();
StringBuilder statementBuilder = new StringBuilder("select * from table where ");
for ( String parameterName : parameterNames ) {
if ( parameterValues.containsKey(parameterName) ) {
statementBuilder.append(parameterName + " = ? AND");
valueList.add(parameterValues.get(parameterName));
}
}
PreparedStatement st = conn.prepareStatement(statementBuilder.toString(),
valueList);
//set each parameter here.
It's only hard the first time; then you can make it generic. That said there are probably query builders that abstract all of this away for you. I use QueryDSL but that does not have bindings for pure JDBC but rather JPA and JDO, etc.
On another forum I was given a different, simpler and cleaner approach that work perfectly.
Here are some links for others with the same problem:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1669972300346534908
http://www.akadia.com/services/dyn_modify_where_clause.html
I have a java.sql.ResultSet object that I need to update. However the result set is not updatable. Unfortunately this is a constraint on the particular framework I'm using.
What I'm trying to achieve here is taking data from a database, then manipulating a small amount of the data and finally the data is being written to a CSV file.
At this stage I think my best option is to create a new result set object and copy the contents of the original result set into the new one, manipulating the data as I do so.
However, I've hunted high and low on Google and don't seem to be able to determine how to do this or whether it's even possible at all.
I'm new to everything Java so any assistance would be gratefully received.
Thanks for the responses. In the end I found CachedRowSet which is exactly what I needed. With this I was able to disconnect the ResultSet object and update it.
What's more, because CachedRowSet implements the ResultSet interface I was still able to pass it to my file generation method which requires an object that implements ResultSet.
The normal practice would be to map the ResultSet to a List<Entity> where Entity is your own class which contains information about the data represented by a single database row. E.g. User, Person, Address, Product, Order, etcetera, depending on what the table actually contains.
List<Entity> entities = new ArrayList<Entity>();
// ...
while (resultSet.next()) {
Entity entity = new Entity();
entity.setId(resultSet.getLong("id"));
entity.setName(resultSet.getString("name"));
entity.setValue(resultSet.getInt("value"));
// ...
entities.add(entity);
}
// ...
return entities;
Then, you can access, traverse and modify it the usual Java way. Finally, when persisting it back in the DB, use a PreparedStatement to update them in batches in a single go.
String sql = "UPDATE entity SET name = ?, value = ? WHERE id = ?";
// ...
statement = connection.prepareStatement(sql);
for (Entity entity : entities) {
statement.setString(1, entity.getName());
statement.setInt(2, entity.getValue());
statement.setLong(3, entity.getId());
// ...
statement.addBatch();
}
statement.executeBatch();
// ...
Note that some DB's have a limit on the batch size. Oracle's JDBC driver has a limit on around 1000 items. You may want to call executeBatch() every 1000 items then. It should be simple using a counter inside the loop.
See also:
Collections tutorial
PreparedStatement tutorial