Getting a list of objects from database - java

I have an object product in my application. This object has a list of items inside it (ArrayList). In the database I have 2 tables: Product and Item. Items have ids of products connected with foreign keys to product id.
It is quite simple to get the Product from database and then get a list of items for it.
How to get a list of products from the database, which will contain all the relevant items inside?
As far as I know, it is not efficient to call dao for every product in the list. How can I manage the query, or object creation to make it more efficient?
I am using Spring JdbcTemplate to get data from Database. Currently I am getting list of products in DAO class and straight from there I call ItemDAO for every item. The database is MySQL.
Update
Okay, probably I was unclear in my first approach. The goal is to get nested lists from Database and how to make it performance-wise.
public class Product {
private Integer id;
private String name;
private String description;
private ArrayList<Item> items;
private Timestamp timeAdded;
}
public class Item {
private String name;
private Float price;
private String type;
private Integer productId;
}
public ArrayList getProducts(String searchName) throws SQLException {
ArrayList<Product> products = new ArrayList<Product>();
String sql = "SELECT * FROM product WHERE name LIKE '%" + searchName + "%'";
List<Map> rows = getJdbcTemplate().queryForList(sql);
for (Map row : rows) {
Product product = setNewProduct(row);
products.add(product);
}
return products;
}
private Product setNewProduct(Map row) {
Product product = new Product();
product.setId((Integer) row.get("id"));
product.setName((String) row.get("name"));
product.setDescription((String) row.get("description"));
ItemsDao itemsDao = (ItemsDao) appContext.getBean("itemsDao");
ArrayList<Item> items = itemsDao.getItems(product.getId());
if (items.size() > 0) {
product.setItems(items);
}
product.setTimeAdded(new java.util.Date(((Timestamp) row.get("time_added")).getTime()));
}
In ItemsDao class I just get a list of items for the product, based on the ID sent.
So the question is how to call list of products and get list of items inside every product? (maybe in one complex SQL statement?). Now the performance is horrible, because when there are 30 products with 10 items each, to get the whole list of products it will have to call database so many times.

The answer is that you can't when using an ORM, they all perform like crap when you have any amount of data. OK if you lazy-load the related collections and only use a few, but if you need to display field from the child objects then you can get 100,000+ queries for a page load. Believe me I just ahd to optimise a page using Doctrine that ran 200,000 queries.
What you have to do is either to paginate the results, or to write a custom query that joins the data and then process the results with a loop control: eg
$sql = "SELECT * FROM table1 t1 JOIN table2 t2 ON t1.id = t2.fk_id";
// run query and get resdults
$cur_prod = '';
While( // fetch a row ){
if($row['prod'] != $cur_prod){
$cur_prod = $row['prod'];
// start the new record in your layout
}
echo $row['t1.f1'];
echo // blah blah blah the related data
}
What I am getting at here is that you have to track the parent product and manage the output when it changes.

Related

How to compare Lists of Integers in DB? Java

We have entity:
Class Drink {
Long id;
String name;
List "Integer" ingredients; // We store ingredient's numbers in this list
}
For example: id = 1, name = Mojito, ingredients = {5,7,3,8}
Let's say, i want to find a drink based on ingredients. How should I do that?
Retrieve all cocktails from data base and iterate through them for comparison?
Or comparison should be conducted in a data-base? If this is correct answer, How can I to that? (How to compare Lists of Integers in the DB)?
Most likely you'll want to filter the data on the database level. The exact solution depends on the type of the database structure and the framework that you use, but since you use PostgreSQL, I assume you have a relational database structure, and since you speak of an "entity", I assume you use something like Hibernate or JPA to interact with it.
Then probably your drinks should reference their ingredients not as numbers, but as entities. This is how the mapping could look like:
class Drink {
Long id;
String name;
#ManyToMany
#JoinTable(tableName = "drink_ingredients")
List<Ingredient> ingredients;
}
class Ingredient {
Long id;
String name;
}
Then a query to find all drinks containing a specific ingredient would be:
Query query = entityManager.createQuery("select d from Drink d "
+ "join d.ingredients i "
+ "where i.name = :ingredientName");
query.setParameter("ingredientName", "Lime");
List<Drink> drinks = (List<Drink>) query.getResultList();

Merging list of two objects to create a third object on the basis of common attribute

I have two different csv files having data on two different entities and I have to merge two different csv files to create one on the basis of sql join type equijoin and left join.
so I have created first entity as class name Customer having attributes:
int CustomerId ;
String CustomerName;
int OrderId;
And List of object of this class like:
Customer c1 = new Customer(CustomerId, CustomerName, OrderId);
1 million objects..
List<Customer> cust = new ArrayList<>();
cust.add(c1);
cust.add(c2);
so on to make list of 1 million object.
Similarly, I have created class of second entity Order having attributes:
int orderId;
String orderName;
Date orderdate;
Order o1 = new Order(orderId, orderName, orderdate);
so on 1 million object
List<Oder> order = new ArrayList<>();
Now I need to merge both the object on the basis of orderId and generate third object having result class having all the attributes from both the classes described above.
Please suggest me solution using java stream 8 to map both the streams of list to create inner join and left join type example in the third new result class.
Aside from the getters, your Customer class should have the following method:
public boolean orderMatch(Order order) {
//fixed the attribute name so it would be in camelCase
return orderId == order.getId();
}
Of course, this implies that Order has a getId() getter method to get its id attribute.
Finally, you'll need a CustomerExtended class.
class CustomerExtended {
int customerId ;
String customerName;
Order customerOrder;
public CustomerExtended(Customer customer, Order order) {
customerId = customer.getId();
customerName = customer.getName();
customerOrder = order;
}
}
Now, you can create a Function which would search for the corresponding Order and append it to a Customer:
Function<Customer,CustomerExtended> extendCustomer = (c) ->{
//I used the more descriptive name orderList instead of o1.
Optional<Order> order = orderList.stream()
.filter(c::orderMatch)
.findFirst();
if(order.isPresent()) {
return new CustomerExtended(c,order.get());
}
return null;
};
And then you can apply it to the Customer list through a map.
List<CustomerExtended> newCustomerList = customerList.stream()
.map(c -> extendCustomer.apply(c))
.collect(Collectors.toList());
EDIT: A few last notes
There should be some check that the ID numbers are not duplicate either when adding the objects to the lists, or when the lists are populated.
For semantic purposes, The Customer object as it is should be renamed CustomerOrder or be separated into an object only for customer info and an object which would store the relation between customer and order.
The case where an order is not found should be better handled and throw an exception.

Category/Subcategory: How to get all subcategories(their subcategories too) for given category?

There is a class Category, with following (significant) properties:
public class Category{
private Integer id;
private String name;
private Category parentCategory;
private Set<Category> subcategories = new HashSet<Category>();
...
//getters and setters
}
I am trying to implement Category/Subcategory concept. One category can have zero or more subcategories. One category can have only one parent category(which can be null). For top level categories parentCategory=null.
Now, I have a list of all categories, List<Category> allCategories = (retrieved from database).
If I have some category (or categoryId), and allCategories, how can I get a list of all subcategories(and their subcategories) for given category? Which loop to use?
(it can be limited to subcategories depth level 3)
Here some pseudo code, if you want more specific solution provide ResultSet details.
for(all result set) {
currentCategoriesFromDb = current category;
currentCategoriesFromDb.setParentCategory() = parentCategoryId;
parentCategory.addCategory(currentCategoriesFromDb )
}
If all category hierarchy is initialized and you want to navigate you can do something like this:
currentCategory.getChildByName(name1).getChildByName(name2);
If you want exact all something recursively :
printbCategories(Category category) {
print(category);
List<Category> subCategories = category.getSubCategories();
for(Category category : subCategories ) {
printbCategories(category);
}
}
Fetching a category tree can be done on a database level using a query. If your Category class is a JPA Entity you can use a query like this:
SELECT c1
FROM Category c1 JOIN c1.subcategories c2 JOIN c2.subcategories c3
WHERE c1.id = :categoryId
This will fetch a category tree with a root of given categoryId. Now if you want to make a flat structure (a list or a set) of a tree, you could use a DFS or BFS algorithm http://en.wikipedia.org/wiki/Tree_traversal.

Java : Set result set from JPA Paginated Query to custom class

Here is the scenario.
I am trying to get a list of records in my resource layer. It has the following code;
PagedResponse<Person> pagedResponse= new PagedResponse<Person>();
There is a call to Business implementation as
pagedResponse = facadeLocator.getPersonFacade().findAllRecords(getUserId(), fromrow, maxrows);
Now in the Business implementation, I use named query as;
Query query = getNamedQuery("Person.findAll");
I have the response as
pagedResponse = executePagedQuery(query, firstResults, maxResults);
and inside executePagedQuery(), I have;
List resultList = query.getResultList();
The response returned pagedResponse is of custom type PagedResponse class with 2 members;
private Long totalRecords;
private List<T> records;
Now in my Person class, I have
#NamedQuery(name = "Person.findAll", query = "Select DISTINCT(p.personName), p.personAge, p.personGender from Person p where p.personAge = :personAge")
Now here is what happens at runtime.
I get the "records" as Vector with members as
[0] = Object[]
[1] = Object[]
Coming back to the resource layer, I want to iterate through the response and set it in a list
List<Person> personList = new ArrayList<Person>();
So what are the options I have.
I have tried doing
for(Object[] person: pagedResponse.getRecords()) {
Person p = new Person();
p.setPersonName((String)person[0]);
// Setting other values
personList.add(p);
}
But it says incompatible types for the line
for(Object[] person: pagedResponse.getRecords()) {
Just to add, I did not face any incompatible type issue when my query did not return select columns and instead returned all the columns like;
query = "SELECT p FROM Person p WHERE
So I have 2 questions;
1. Why was there no type casting issues when I was returning all the columns using the named query (It showed the type as "Person" and not generic type as showing after using the named query with specific columns)
2. Using the query with specific columns, what is the right approach to set the values returned from the query in the resource layer ?
The query with many individual SELECTed values is supposed to return a list of lists. Maybe you want to define a bean with an appropriate constructor:
package com.foo;
public class PersonData {
private String name;
private int age;
private Sex gender;
public PersonData(String name, int age, Sex gender) {
this.name = name;
this.age= age;
this.gender = gender;
}
// getters/setters
}
And run the query as:
SELECT NEW com.foo.PersonData(DISTINCT(p.personName), p.personAge, p.personGender)
FROM Person p WHERE p.personAge = :personAge
Now getResultList() should return a list of PersonData objects. Though I haven't used the nested new PersonData(DISTINCT(...)) syntax...

Persist collection in object with MyBatis

I have POJO classes:
class Ticket {
private int id;
private double cost;
private Date time;
private List<Place> places;
// Getters and setters here
}
class Place {
private int row;
private int place;
// Getters and setters here
}
Then I create one ticket and some places:
Ticket ticket = new Ticket();
ticket.setCost(58.7);
ticket.setTime(new Date());
Place place1 = new Place();
place1.setRow(1);
place1.setPlace(2);
ticket.addPlace(place1);
Place place2 = new Place();
place2.setRow(3);
place2.setPlace(4);
ticket.addPlace(place2);
And now I want to save it to DB:
session.insert("insertTicket", ticket);
session.commit();
In MapperConfig.xml I write this lines:
<insert id="insertTicket" parameterType="Ticket">
INSERT INTO tickets (cost, time) VALUES (#{cost}, #{time})
</insert>
How I can save List places in automatic mode?
Does MyBatis can save it for me?
Or I need to iterate manually with foreach and insert every Place by hand?
Thanks for any help.
Even though MyBatis is able to support the reverse direction (i.e. filling the list during a query with a nested select or from a join), there is no automatic mode that inserts the containing list into the database.
According to this Google Groups discussion you have to insert the list elements manually.

Categories