I'm trying to pass a List to Postgresql using Mule ESB.
A simplfied version of my pojo looks like:
public class NewEntry {
private String positionReference;
private String productID;
#XmlElement(required=true, name="PositionReference")
public String getPositionReference() {
return positionReference;
}
public void setPositionReference(String positionReference) {
this.positionReference = positionReference;
}
#XmlElement(required=true, name="ProductID")
public String getProductID() {
return productID;
}
public void setProductID(String productID) {
this.productID = productID;
}
}
This is passed in via a soap webservice as
List
until now i've had it simply being transformed into JSON and pumped it out to a file now I would like to insert it into a database, so in my database step I've put a in insert query in along the lines of:
<jdbc:query key="insertrecord" value="INSERT INTO f_intraday_rt(version) VALUES (#[message:productDescription]);"/>
Anyway no matter what message evaluation I use in the VALUES section, I can't get it to insert a value, just errors or blank rows.
How do I unbundle the loop and insert a row per list item?
Thanks
Tom
Use a collection splitter to split the list of objects into different messages just before your outbound JDBC endpoint. This will perform multiple inserts.
It's one INSERT per entry in the List, so you should loop over the collection and execute the SQL INSERT for each one.
Best to think about batching and transactions. Are they one unit of work?
Related
Hi there I like to use at Apache Ignite a Pojo which has a HashMap attribute so I can work with dynamic models at runtime. Storing and Saving of such objects works fine.
However, I m wondering if there a way exist to access the key / values of such a Hashmap through a SQL query? If this is not supported any other ways I can work in Apache Ignite with dynamic objects?
POJO Class with dynamic attributes
#Data
public class Item {
private static final AtomicLong ID_GEN = new AtomicLong();
#QuerySqlField(index = true)
private Long id;
#QuerySqlField
public Map<String,Serializable> attributes = new HashMap<String,Serializable>();
public Item(Long id, String code, String name) {
this.id = id;
}
public Item() {
this(ID_GEN.incrementAndGet());
}
public void setAttribute(String name,Serializable value) {
attributes.put(name, value);
}
public Serializable getAttribute(String name) {
return attributes.get(name);
}
}
Example Query Feature illstrated
SqlFieldsQuery query = new SqlFieldsQuery("SELECT * FROM Item WHERE attributes('Price') > 100");
SQL in Ignite is not just syntactic sugar, it requires a schema of your models to be defined before you can run SQL queries and this won't work for a collection. Therefore you need to normalize the data just like with a regular DB or rework the model's structure somehow to avoid JOIN.
Apache Ignite has no support for destructuring/collections in its SQL, so you can't peek inside HashMap via SQL.
However, you may define your own SQL functions, so you can implement e.g. SELECT hashmap_get(ATTRIBUTES, 'subkey') FROM ITEM WHERE ID = ?
But you can't have indexes on function application so the usefulness is limited.
For a simple Java REST-API I created a save function to persist my model to a DynamoDB table.
The model uses a auto generated range key as you can see here:
#DynamoDBTable(tableName = "Events")
public class EventModel {
private int country;
private String id;
// ...
#DynamoDBHashKey
public int getCountry() {
return country;
}
public void setCountry(int country) {
this.country = country;
}
#DynamoDBRangeKey
#DynamoDBAutoGeneratedKey
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
//...
}
Unfortunately the the DynamoDBMappers .save() method does not return anything. I want to return the created item to set the proper location header in my 201 HTTP response.
public EventModel create(EventModel event) {
mapper.save(event);
return null;
}
How can I make that work? Any suggestions? Of course I could generate the id on the client but I don´t want to do this because solving the potential atomicity issue needs additional logic on client- and server-side.
I´m using the aws-java-sdk-dynamodb in version 1.11.86.
Never mind, I figured out how to do it. The .save() method updates the reference of the object. After calling mapper.save(event); the id property is populated and has its value.
So the way to get it work is just:
public EventModel create(EventModel event) {
mapper.save(event);
return event;
}
That´s it!
There is direct way through dynamo db mapper to get what is saved in dynamodb after put/update Approach mentioned by m4xy# would work if you are saving with DynamoDBConfig as CLOBBER or UPDATE. If you are using UPDATE_SKIP_NULL_ATTRIBUTES, this approach won't work.
If you are using mapper, you have to specifically call db again to get existing value (which might have been updated if there are multiple writers and you might get unxpected result). To ensure read that you expect you can implement locking for write such that if lock is acquired by a given thread, no other thread can write for a given key. But, this approach as a downside of slowing down your application.
Alternatively, you can use dynamoDBClient that has apis to support return db values after write.
https://sdk.amazonaws.com/java/api/2.0.0-preview-11/index.html?software/amazon/awssdk/services/dynamodb/DynamoDbClient.html
Well that's really embarrassing I have made a standard pojo class and its dao class for data retrieval purpose. I am having a difficulty to understand a basic procedure to how to handle a customized query data to Pojo class.
let's say my User class is
public class User{
private int userId;
private String username;
private int addressId;
}
public class Address{
private int addressId;
private String zip;
}
public class UserDAO{
public void getUserDetails(){
String getSql = select u.userId, u.username, a.zipcode from user u, address a where u.addressId = a.addressId;
//no pojo class is now specific to the resultset returned. so we can't map result to pojo object
}
}
now how I should model this with my pojo class as if using String to manage this then concept of object oriented vanishes, also complexity would increase in the future as well. kindly guide!
Update for Further Explanation
We know that we can map same table objects with same pojo class, but when the query is customized and there is a data returned which doesn't map to any specific class then what would be the procedure? i.e. should we make another class? or should we throw that data in a String variable? kindly give some example as well.
For this purpose you can use one of implementation of JPA. But as you want to do it manually I will give you small example.
UPD:
public class User {
private int userId;
private String username;
private Address address; // USE POJO not ID
}
public class Address{
private int addressId;
private String zip;
List<User> users;
}
public User getUserById(Connection con, long userId) {
PreparedStatement stmt;
String query = "select u.user_id, u.user_name, a.id, a.zip from user u, address a where a.address_id = u.id and u.id = ?";
User user = new User();
Address address = new Address;
try {
stmt = con.prepareStatement(query);
stmt.setLong(1, userId);
ResultSet rs = stmt.executeQuery();
address.setId(rs.getInt("id"));
address.setZip(rs.getString("zip");
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("user_name"));
user.setAddressId(rs.getInt("address_id"));
user.setAddress(address); // look here
} catch (SQLException e) {
if (con != null) {
try {
System.err.print("Transaction is being rolled back");
con.rollback();
} catch (SQLException excep) {
}
}
} finally {
if (stmt != null) {
stmt.close();
}
}
return user;
}
You shouldn't do new POJO for that query, you should write normal query. And remember - your object model is main, tables in DB is just a way to save data of your application.
We know that we can map same table objects with same pojo class, but when the query is customized and there is a data returned which doesn't map to any specific class then what would be the procedure? i.e. should we make another class?
JPA dynamic instantiation allows you to define a query with a POJO whose constructor specifies only the fields and types you want from the database.
This will perform a JPA selection which will return a List.
If you need to change the query later and the columns are unchanged, your POJO will still work.
If you change the columns, then also change the POJO accordingly.
NOTE:
You must specify fully qualified package and constructor arguments.
Type User must be a JPA-mapped or JPA-annotated entity class.
The entityManager is in JPA EntityManagerFactory.
TypedQuery<User> q;
String sql = "select new com.stuff.User(
int u.userId, String u.username, String a.zipcode)
from User u, Address a where u.addressId = a.addressId";
List<User> list = entityManager.createQuery(sql).getResultList();
for(User u : list) {
doStuff(u);
}
Dynamic instantiation is also handy when you want to select specified columns, but avoid those columns with large data, such as BLOB types.
For example, maybe you want a list of proxy POJO's which represent the fully populated thing, but are themselves not fully populated.
You present the proxy list, and when the user selects one, then you do another query to get the fully populated object.
Your mileage may vary.
There's many ORM frameworks that can do this including Hibernate, myBatis, JPA and spring-JDBC
spring-jdbc and myBatis give you granular control over the SQL whereas with JPA and Hibernate you are usually abstracted away from the SQL.
I suggest you do some reading and figure out which one you like before rolling your own solution.
Your question:
We know that we can map same table objects with same pojo class,
but when the query is customized and there is a data returned
which doesn't map to any specific class then what would be the procedure?
If you have 100 kinds of SQL which returns different combination of columns, could it be to create 100 different POJOs? The answer is "NO, stop using POJO".
This library qood is designed to solve this problem, you can try it.
Let's say I have a method in java, which looks up a user in a database and returns their address and the team they are on.
I want to return both values from the method, and don't want to split the method in two because it involves a database call and splitting involves twice the number of calls.
Given typical concerns in a moderate to large software project, what's the best option?
whatGoesHere getUserInfo(String name) {
// query the DB
}
I know the question smells of duplication with existing ones, but each other question had some element that made it different enough from this example that I thought it was worth asking again.
you have some options.
The most OOP it will be create a class to encapsulate those 2 properties, something like that
private class UserInfo {
private Address address;
private Team team;
}
Or if you want a simple solution you can return an array of objects:
Object[] getUserInfo(String name) {
// query the DB
return new Object[]{address,team};
}
Or if you want to expose this method to some library you can have some interface that it will consume those properties, something like this:
class APIClass{
interface UserInfo{
public Address getAddress();
public Team getTeam();
}
UserInfo getUserInfo(String name) {
// query the DB
return new UserInfo(){
public Address getAddress(){ return address; }
public Team getTeam(){ return team; }
};
}
}
cant a map help , A MultivalueMap. Where the key is the user name and the 2 values are the adress and the team name. I am assuming both your Address and team are String variables, You can know more about Multivalue Map here
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/MultiValueMap.html
http://apachecommonstipsandtricks.blogspot.in/2009/01/multi-value-map-values-are-list.html
First model your abstractions, relationships and multiplicity well (see an e.g. below). Then you can model tables accordingly. Once these two steps are performed you can either leverage JPA that can be configured to load your object graph or you write JDBC code and create the graph your self by running a SQL query with proper SQL JOINs.
A User has an Address
A Team can have 1 or more Users (and can a User play for more teams?)
You can return a String array with user name and group name in it . The method looks like :
public String[] getUserInfo(String name) {
String[] result = new String[2];
// query the DB
...
result[0] = userName;
result[1] = groupName;
return result;
}
A common solution to this kind of issue is to create a custom object with as many attributes as the values you want to return.
If you can't create a new class for this, you can use a Map<String, Object>, but this approach is not type-safe.
I thought Guava had a generic Pair class already, but I cannot find it. You can build your own using generics if you're on Java 1.5+.
public class Pair<X,Y>
{
public final X first;
public final Y second;
public Pair(X first, Y second) {
this.first = first;
this.second = second;
}
}
Feel free to make the fields private and add getters. :) Using it is easy:
return new Pair<Address,Team>(address, team);
Update
Apache Commons Lang has Pair. See this SO question for more options.
I've a problem with a query that returns multiple value using Spring 3.
I'm using this to retrieve values, but the TemplateFlow objects returned from DB are always null (all field contains null or default value).
List<TemplateFlow> flows = (List<TemplateFlow>) getJdbcTemplate().query(
sqlString,
ParameterizedBeanPropertyRowMapper.newInstance(TemplateFlow.class)
);
TemplateFlow is a class that contains all field. I'm retrieving some values after an update, is it possible I need to commit the changes? (but I'm not using any kind of transaction).
public class TemplateFlow {
private int id_templateflow;
private int id_templateprocess;
public int id_templateflow() { return this.id_templateflow; }
public void id_templateflow(int id_templateflow) { this.id_templateflow = id_templateflow; }
public int id_templateprocess() { return this.id_templateprocess; }
public void id_templateprocess(int id_templateprocess) { this.id_templateprocess = id_templateprocess; }
}
I I try to run the query directly on DB it returns two rows.
thanks for help!
Andrea
Your TemplateFlow class does not conform to the javabean pattern, and ParameterizedBeanPropertyRowMapper requires this to be the case:
Column values are mapped based on matching the column name as obtained from result set metadata to public setters for the corresponding properties.
For example, you should have
int getId_templateflow()
void setId_templateflow(int)
instead of
int id_templateflow()
void id_templateflow(int)
However, I'd advise against using ParameterizedBeanPropertyRowMapper at all - it couples your database too tightly to your code, and that's not a good thing. Consider instead writing your own implementation of RowMapper.