How to compare Lists of Integers in DB? Java - 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();

Related

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.

HQL: How to query certain fields when one of those fields is a one-to-many List?

I am having difficulty writing a HQL query to select ONLY the caseid, title, and caseStatus fields from my Cases entity. The cases returned have to be distinct based on caseid. I do not want the name and userid fields to be included. I also do not want to use Lazy fetching for caseid, title, and caseStatus fields. Note that the caseStatus field is a one-to-many List. Below are the entities. The getters/setters are omitted to save space.
#Entity
#Table(name = "Cases")
public class Cases {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "caseid", nullable = false)
private Integer caseid;
private Integer userid;
private String name;
private String title;
#OrderBy("caseStatusId DESC")
#OneToMany(mappedBy = "cases", fetch = FetchType.EAGER)
private List<CaseStatus> caseStatus;
}
#Entity
#Table(name = "CaseStatus")
public class CaseStatus {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "caseStatusId", nullable = false)
private Integer caseStatusId;
private String info;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "caseid")
private Cases cases;
}
My goal is to retrieve a distinct List<Cases> or List<Object[]> of the Cases entity containing only caseid, title, and a List<CaseStatus>. The List<CaseStatus> will contain CaseStatus objects with all of its fields populated.
public List<Object[]> getCases(String title) {
TypedQuery<Object[]> q = em.createQuery("select distinct c.caseid, c.title, cs "
+ "FROM Cases c join c.caseStatus cs "
+ "where c.title like :title", Object[].class);
q.setParameter("title", "%" + title + "%");
List<Object[]> results = q.getResultList();
return results;
}
The above method is close, but not correct because rather than returning a List<CaseStatus> in one of the indexes, it is only returning a single CaseStatus entity.
For example, if my DB contains a single Case with a List<CaseStatus> having a size of n for example, the results will be similar to the example below:
Example of results I'm getting now. Not correct:
List<Object[]> index 0:
Contains an Object[] where:
Object[0] = {some caseid}
Object[1] = {some title}
Object[2] = {1st CaseStatus}
List<Object[]> index 1:
Contains an Object[] where:
Object[0] = {same caseid as the one found in index 0 above}
Object[1] = {same title as the one found in index 0 above}
Object[2] = {2nd CaseStatus}
...
List<Object[]> index n-1:
Contains an Object[] where:
Object[0] = {same caseid as all the previous}
Object[1] = {same title as all the previous}
Object[2] = {nth CaseStatus}
Example of results I hope to achieve:
List<Object[]> index 0:
Contains an Object[] where:
Object[0] = {unique caseid}
Object[1] = {some title}
Object[2] = List<CaseStatus> with size of n
Updated the question. Instead of name, title, and List<CaseStatus>, the fields I want to retrieve are caseid, title, and List<CaseStatus>. caseid is the primary key of Cases.
I found various threads Select Collections with HQL - hibernate forum and Select collections with HQL - stackoverflow. It's pretty much the problem I ran into. Looks like no one found a solution in these threads.
Hibernates a bit confused about the query; in HQL do your join like this (apologies, I've not been able to test before posting due to wonky computer, but you should get the idea)
select distinct c from Cases c left join fetch c.caseStatus cs where....
the "fetch" makes it eager. Note that this will return an array of type Cases. You where clauses look about right.
In fact HQL is fully object-oriented and uses your classes structure in the Query, so by writing c.caseStatus HQL expects that your Cases class has a caseStatus property, which is wrong because it's a collection.
If you take a look at Hibernate HQL documentation you can see that:
Compared with SQL, however, HQL is fully object-oriented and understands notions like inheritance, polymorphism and association.
I think what you need to do here is to change your query so it matches your classes structures:
Query q = em.createQuery("select distinct c.name, c.title, cs.caseStatus FROM Cases c left join c.caseStatus where "
+ "c.name like :name and "
+ "c.title like :title");
Correct syntax should be
TypedQuery<Object[]> q = em.createQuery("select c.name, c.title, cs FROM Cases c "
+ "join c.caseStatus cs where "
+ "c.name = :name and "
+ "c.title = :title", Object[].class);
Return type will be List<Object[]>, where in first index of Object[] is c.name, second is c.title and third is associated caseStatus entity. It is possible to query for multiple instances (rows).
We need JOIN because relationship between CaseStatus and Case is mapped via collection.
SELECT cs
FROM Case c JOIN c.cases cs;
Why don't you just use
Query q = em.createQuery("select distinct c from Cases c where "
+ "c.name like :name and "
+ "c.title like :title");
Just try this. This may be a naive approach but should be able to solve the problem. You may be getting more fields than you required but the return type would be list of Cases.

Getting a list of objects from database

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.

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.

Hibernate: Criteria with collections

I have a problem with hibernate and criterias. I have two Classes:
public class Place{
long id;
String name;
Set<Street> streets;
}
public class Street{
long id;
String name;
Place place;
}
I now want to write a method which returns a list of places with a name like given in parameters and a street named like given in parameters.
public List<Place> findPlaces(String name, String streetname){
//getSession() gives me a hibernate session
Criteria crit = getSession().createCriteria(Place.class, "place");
crit.add(Restrictions.like("name", name+"%"));
//Everything works fine until here
//Last step: Sort out all places not containing a street named like streetname + "%"
}
I tried different ways for the last step:
//streetList is a list of all streets named like streetname
crit.add(Restrictions.in("streets", streetList));
Another way:
DetachedCriteria strasseCrit = DetachedCriteria.forClass(Street.class, "street");
streetCrit.add(Restrictions.like("street.name", streetname + "%"));
streetCrit.createAlias("street.place", "streetPlace");
streetCrit.add(Restrictions.eqProperty("streetPlace.id", "place.id"));
streetCrit.setProjection(Projections.property("street.name"));
crit.add(Subqueries.exists(streetCrit));
last way:
crit.createAlias("place.streets", "street");
crit.add(Restrictions.like("street.name", streetname + "%"));
crit.setResultTransformer(DistinctResultTransformer.INSTANCE);
I hope you can understand my problem and sorry for my bad english :(
I searched for a solution for two days and I do not know how to go on...
Greetings form Germany :)
Philipp
public List<Place> findPlaces(String name, String streetname){
Criteria crit = getSession().createCriteria(Place.class, "place");
criteria.createAlias("streets", "s"); // Create alias for streets
crit.add(Restrictions.like("s.name", name+"%"));
// continue method
}

Categories