How to append two value to one key using Redis Spring Data - java

I using redis caching my project but i have a problem. I had model student and write method put it to redis.First method i write findStudent one week and put it to cache.
public void findStudentOneWeek(List<Student> students1) {
redistemplate.opsForHash().put("Student", student.getId(), List<Customers>);
}
Second method I write findStudent one day.
public void findStudentOneDay(List<Student> students2) {
redistemplate.opsForHash().put("Student", student.getId(), List<Customers>);
}
But i want total user from 8 day. It mean i want hold one key Student but new value equal total value method findStudentOneWeek + total value method findStudentOneDay. But i don't now how to do. I can't find method working it. I know method put from redis but it remove old value and save new value. I don't want it. I want value total.

Firstly, I assume a typo, where List<Customers> should be List<Students> student:
redistemplate.opsForHash().put("Student", student.getId(), List<Students> students);
Spring Data class HashOperations works on the similar principle as HashMap. Both allow you to get the value by the key (and the hash key in case of HashOperations). Read the current value List<Customers> and put them with a new value to the template.
List<Students> students = redistemplate.opsForHash().get("Student", student.getId());
students2.addAll(students);
redistemplate.opsForHash().put("Student", student.getId(), students2);

Related

How to convert a object from one JpaRepository into another JpaRepository

I have a problem with one functionality in my spring app. I have 2 tables in the same database, both contains the same type of data (id,title,description and date). And I can get the data from one table but don't know how to insert into 2nd table.
In my #Service layer i can get the data from table A. But dont know how to convert into another class object (both classes contain the samne data)
Injected JpaRepositories
private TasksRepository theTasksRepository;
private TasksRepositoryArchive theTasksRepositoryArchive;
And there's code to get the object from table A (TasksRepository - JpaRepository)
public Tasks findById(int theId) {
//Check if value is null or not null
Optional<Tasks> result = theTasksRepository.findById(theId);
Tasks theTask = null;
if (result.isPresent())
{
//if value is not null
theTask = result.get();
}
else
{
//if value is null
throw new RuntimeException("Task with given ID couldn't be found " +theId );
}
return theTask;
}
1) Define 2 entities, one for each table. To copy data, create an instance of the 2nd type and, copy properties, save. To copy properties there are many ways: you cann call each getter and setter manually, you can use some libraries like Dozer or MapStruct. Don't forget to set ID to null.
2) If you want to have an archive of changes, use libraries that help to implement it. For instance, consider using Enverse.

Is it a good practice to make a DAO class Comparable type

This is my sample mapping in hibernate
class ApplnDoc {
AdmAppln admAppln;
// getters and setters
}
class AdmAppln {
Set<Student> student;
// getters and setters
}
class Student {
int id;
String registerNo;
AdmAppln admAppln;
// getters and setters
}
In ApplnDoc table we are storing images of all candidates. AdmAppln is for storing admission details, Student is for storing student details. Even if AdmAppln is having a Set of Student, only one record of Student will be present for a particular AdmAppln id (under one AdmAppln only one Student).
Now I want to write few data from to these tables, into an Excel file, whose records must be sorted in the order of registerNo (if it is present), otherwise using id of the Student. We are using XSSFWorkbook class under org.apache.poi.xssf.usermodel package for doing operations on Excel sheet. Here I found a way to sort the excel sheet, but I tried and found a way in code itself using Comparable interface.
This is what I did in ApplnDoc class
public int compareTo(ApplnDoc otherData) {
if(new ArrayList<Student>(this.admAppln.getStudents()).get(0).getRegisterNo() != null &&
!new ArrayList<Student>(this.admAppln.getStudents()).get(0).getRegisterNo().isEmpty() &&
new ArrayList<Student>(otherData.admAppln.getStudents()).get(0).getRegisterNo() != null &&
!new ArrayList<Student>(otherData.admAppln.getStudents()).get(0).getRegisterNo().isEmpty()) {
return new ArrayList<Student>(this.admAppln.getStudents()).get(0).getRegisterNo()
.compareTo
(new ArrayList<Student>(otherData.admAppln.getStudents()).get(0).getRegisterNo());
} else {
return new ArrayList<Student>(this.admAppln.getStudents()).get(0).getId() -
new ArrayList<Student>(otherData.admAppln.getStudents()).get(0).getId();
}
}
Since there is no get() method in Set interface the only way to get Student's registerNo from AdmAppln was to convert it to a list. Then I sorted the list and then it was iterated to generate the excel file.
Is the above mentioned comparison mechanism a proper one or is there a better way? Why I am asking this question because when the Hibernate session is closed and in my compareTo if I'm accessing the child table columns, then I will be getting Invocation exception.
There are some thing worth discussing here:
1-
Even if AdmAppln is having a Set of Student, only one record of
Student will be present for a particular AdmAppln
Why?
is this something you have no control over or is there any particular reason to keep a set where is not needed? (also im assuming a #OneToMany instead of a #OneToOne mapping)
2-
This lead to the child object beig lazy fetched (N.B this is an assumption since you didn't post relevant code about mappings or how you fetch the entity from db).
This means that you have to either switch to eager fetching in the entity (unrecommended) or specify it when fetching the entities
3-
Also please refactor that compareTo and use variables
public int compareTo(ApplnDoc otherData) {
Student thisStudent = new ArrayList<>(this.admAppln.getStudents()).get(0);
Student otherStudent = new ArrayList<>(otherData.admAppln.getStudents()).get(0);
if(thisStudent.getRegisterNo() != null &&
!thisStudent.getRegisterNo().isEmpty() &&
otherStudent.getRegisterNo() != null &&
!otherStudent.getRegisterNo().isEmpty()) {
return thisStudent.getRegisterNo().compareTo(otherStudent.getRegisterNo());
} else {
return thisStudent.getId() - otherStudent.getId();
}
}
While nothing wrong with that comparison mechanism (except the NullPointer if you have an empty Set of student) you should use the database ordering when querying.
If you still want to compare that way you just have to make sure you have everything you need fetched before closing the session.
You need to load the entire object tree before closing the session else you will get Exception. By the way you can always sort records with the query itself.

Hashtable returning null but object key is present

EDIT: FML! MY implementation of hashcode had a lowercase c. -.-
I've been trying to learn TDD and have been following the 'By Example' book by Kent Beck; it's very good!
However, I can't seem progress because a value is returning null when I access a hashtable. I've run a debug session and the object with the value is clearly there yet the result is null.
The code to build and access is:
public void addRate(String from, String to, int rate){
this.rates.put(new Pair(from, to), new Integer(rate));
}
from and to are "GBP" and "USD". Also verified by debug.
Test case calling the above:
#Test
public void testreduceMoneyDifferentCurrency(){
Bank bank = new Bank();
bank.addRate("GBP", "USD", 2);
Money result = bank.reduce(Money.gbpound(2), "USD");
assertEquals(Money.dollar(1), result);
}
The reduce method in bank calls the method rate:
public Money reduce(Bank bank, String to){
int rate = bank.rate(this.currency, to);
return new Money(this.amount / rate, to);
}
Which is where the issue is:
public int rate(String from, String to){
if (from.equals(to)) return 1;
Integer rate = (Integer) this.rates.get(new Pair(from, to));
return rate.intValue();
}
The first line copes with USD -> USD conversions etc.
The Pair object is 2 strings built to be used as a key.
I've not used has tables a great deal but I can't see what the issue is, I know for certain that the values are in the hashtable but 'rate' is always returning a null value.
I can't see the wood for the trees. :) Could someone point me in the right direction please?
I think the problem is in the Pair method.
When you do this:
this.rates.get(new Pair(from, to));
you are creating a new instance of Pair, which is not the same as the one you've put into the map in the addRate method.
If you want the code to work correctly, you either have to use the same instance of Pair class or correctly implement equals and hashCode method on Pair class.
Here's a bit deeper insight into the inner working on HashMap and what you have to do to make it work: https://stackoverflow.com/a/6493946/2266098
Java keeps the reference of objects. So when you are trying to do this
this.rates.get(new Pair(from, to));
you are basically creating a new instance of Pair which does not exists as a key in your HashMap.

How to search an array of objects and then update a part of the object in java?

I have an Array of objects. Each object is a customer record, which is the customer ID (int), first name (String), last name(String), and balance (double).
My problem is that i am not supposed to have duplicate customer records, so if they appear in the file twice, I have to just update their balance. I cannot figure out how to search the array to find out if i need to just update the balance or make a new record in the array.
I feel like i should do this in the get/setters, but i am not exactly sure.
edit: to clarify on "if they appear in the file twice, I have to just update their balance." I have a file i made in notepad which is supposed to be a customer list, which has all of their information. if the same customer shows up twice, say the following day to buy more stuff, i am not supposed to create a new object for them since they already have an object and a place in the array. instead, i am supposed to take the amount they spent, and add it to their already existing balance within their existing object.
edit2: i thought i would give you the bit of code i have already where i read in the values into the array. i based this off of the example we did in class, but we didn't have to update anything, just store information into an array and print it if needed.
public CustomerList(){
data = new CustomerRecord[100]; //i'm only allowed 100 unique customers
try {
Scanner input = new Scanner(new File("Records.txt"));
for(int i = 0; i < 100; ++i){
data[i] = new CustomerRecord();
data[i].setcustomerNumber(input.nextInt());
data[i].setfirstName(input.next());
data[i].setlastName(input.next());
data[i].setTransactionAmount(input.nextDouble());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
You shouldn't be using arrays in that case. A Set would be much more suitable as it, by definition, does not have duplicate entries.
What you need to do is to implement the equals() and hashCode() methods in your Customer class so they only use id (or id and name fields) but not balance.
If for some reason you need to use arrays you have two options:
sort the array and use binary search to find if the customer is there, this is nice if the array doesn't change much but you're doing a lot of updates
simply do a linear scan of the array, checking each entry to see if a given customer is already there, if so then update the balance, otherwise add it as a new entry
It would be something like:
public void updateOrAdd(Customer cst) {
boolean exists = false;
for(Customer existing : array) {
// !!! You need to implement your own equals method in the
// customer so it doesn't take into account the balance !!!
if(existing.equals(cst)) {
exists = true;
existing.updateBalance(cst.getBalance());
break;
}
}
if(!exists) {
// add the cst to the array
}
}
The difference is in runtime, the set solution will be constant O(1) on average (unless you incorrectly implement your hashCode() method).
Suppose you have a Customer array:
Customer[] customers = new Customer[size];
... // fill the array with data
Then you get a new customer object called newCustomer. You need to search for newCustomer in your array and, update it if it is already there, or add it if it's not. So you can do something like this:
// Return, if it exists, a customer with id equal to newCustomer.getId()
Optional<Customer> existingCustomer =
Arrays.stream(customers)
.filter(c -> newCustomer.getId().equals(c.getId()))
.findFirst();
if (existingCustomer.isPresent()) {
// update the customer object with newCustomer information as appropriate
Customer customer = existingCustomer.get();
// assuming you have an updateBalance() method
customer.updateBalance(newCustomer.amountSpent());
} else {
// if the customer is not in the array already, add them to the current position
customers[currentIndex] = newCustomer;
}

Storing and comparing against objects from a database

I am working on an android app that loads in a list of students to display in a list based activity. There are two components to the app. There is a server which responds via xml with the list of current active students and a database on the app end which stores theses students with some details (name,age etc). I would like a way to sync these two data sources. When the app starts, I would like to check against the xml to see if students on the server were added/deleted and update the db accordingly.
I would be parsing the xml list into a student object at login. Is there any way to store/retrieve an entire object into an android supported db so I can do a direct comparison to see what to update/delete? It would end up being something like
if (serverStudent[0].name == dbStudent[0].name)
//overwrite dbStudent object with serverStudent fields
What is the most efficient/lightweight way to achieve object persistance and then comparison in Android?
Here's a method I have used in the past:
Anytime an object in the database is changed, use a timestamp column to store that time. When the app connects on startup, simply check each timestamp in the app db against the timestamp in the server db for each object. If the timestamps match, do nothing. If the timestamps don't match, retrieve the updated record from the server. Make sure you're using a detail enough timestamp (usually down to milli- or micro- seconds).
The nice thing about timestamps is that if you don't want the server data to override the app data, you could look at which is newer and keep that object if they've both been edited. Just adding some additional thoughts!
You can do something like this -
public class StudentRecord {
Vector<StudentData> studentDatas;
public StudentRecord()
{
studentDatas = new Vector<StudentData>();
}
public Vector<StudentData> getRecords() {
return studentDatas;
}
public void setRecords(Vector<StudentData> records) {
this.studentDatas = records;
}
public class StudentData
{
String name,Rollno;
public String getRollno() {
return Rollno;
}
public void setRollno(String rollno) {
Rollno = rollno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
When you get the vector object studentDatas you can do something like this -
for(Object object : record.getRecords())
{
data = (StudentData)object;
data.getRollno();
data.getName();
}
Check out these libraries:
http://www.datadroidlib.com/
https://github.com/octo-online/robospice
I believe both offer solutions for your situation.
Or you can roll your own solution... Basically you will want to create a service or asynctask to do the syncing, in your student object you can create a constructor that you can pass an id to and have it pull the appropriate record from your local db then make a comparison method that will update if newer information is available.
I'm not sure i understood your question correctly.But as far as i understand i would do something like this.
In server side send send Json array which holds json student objects.
In android side create similer Student class and override equals
method as you want.
Then for each student check with equals method whether they are
equals or not and take action accordingly.
If you want to make faster search in students object array then apply
hash map instead of arrays.

Categories