I have a very slow code here. All it does is that it colleting all rows with a specific entity column.
List<Data> slectedData = dataService.findByJobNameOrderByDateTime(selectJob.getValue().getName());
List<Data> deleteThese = slectedData.subList(firstIndex - 1, lastIndex);
for (List<Data> deleteTheseLists : Lists.partition(deleteThese, 2000)) {
dataService.deleteInBatch(deleteTheseLists);
}
Then I create a sub list and I want to delete that sublist.
But the sublist can be very large and then dataService.deleteInBatch(deleteTheseLists); takes alot of time.
The entity class Data looks like this:
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class Data {
// ID
#Id
#GeneratedValue
private long id;
// Made by
private String jobName;
private String calibrationName;
#Column(columnDefinition = "DATETIME(3)")
private LocalDateTime dateTime;
// Analog input
private float sa0;
private float sa1;
private float sa1d;
}
And I want to delete on dateTime. Is that possible in Spring Boot JPA?
Because I can't delete on id because the id key is not correct indexed in the database because sometimes the database takes long time to insert data, and sometimes it goes fast. So it's a very unsecure way to delete entities in JPA.
Yes you can delete by dateTime using keywords
//equals
deleteByDateTimeEquals(LocalDateTime dateTime);
// lessthan
deleteByDateTimeLessThan(LocalDateTime dateTime);
// greaterthan
deleteByDateTimeGreaterThan(LocalDateTime dateTime);
Related
I am trying to read data from another table based on the value of one of the fields in the current entity. But somehow I am facing an issue selecting multiple fields inside the formula.
#Entity
#Table(name = "contacts")
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class ContactInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "url")
private String imageUrl;
//Not working
#Formula("(select code,area from areas where area_id=id)")
private Map<String, String> vals;
//working
#Formula("(select code from areas where area_id=id)")
private String someVal;
}
is there any way that I can use the formula for retrieving multiple columns of data with multiple rows?
Thanks for your help.
I'm not sure you can retrieve like Map<string, String>. Suppose you declare another field how you going to retrieve. you can receive as a List instead of Map<st..., str..>.
Instead of #Formulae, you can use #OneToMany & #ManyToOne. through a Bi-direction connection, you achieve your scenario.
This looks more like it should be using JPA's ElementCollection mapping to the Area table, with a MapKeyColumn mapping:
public class ContactInfo {
..
#ElementCollection
#MapKeyColumn(name="code")//key
#Column(name="area") //value
#CollectionTable(name="areas",
joinColumns=#JoinColumn(name="area_id"))//fk from Areas->contacts.id
private Map<String, String> vals;
..
See this for some more information and examples.
I want to ask about what is the most efficient way to search about specific data from a database without doing a for loop in all of the records?
I have a project on java spring and I have this Entity:
#Entity
#Table(name = "USERS") public class USERS {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "UID")
private Integer id;
#Column(name = "FName")
private String firstName;
#Column(name = "SName")
private String secondName;
#Column(name = "TName")
private String thirdName;
#Column(name = "LName")
private String fourthName;
#Column(name = "Email")
private String email;
#Column(name = "PW")
private String password;
#Column(name = "MNumber")
private String mobileNumber;
#Column(name = "ISDeleted")
private boolean isUserDeleted;
//---------------------- Getters and Setters ----------------------
and I made this service:
public List<USERS> findAllActive() {
List<USERS> usersList = new ArrayList<USERS>();
for (USERS users: usersRepository.findAll()){
if (!users.isUserDeleted()){
usersList.add(users);
}
}
return usersList;
}
For example; I have one property for User, if he is active or not.
So, my question; what is the most efficient way to do get specific data like retrieving all of the active users from the DB without doing a for loop like in the code above? Because if the list of users is a 1 Million or more, it could have performance issues.
Assuming that you are using JpaRepository then you can create custom query.
#Query("SELECT u FROM USERS u WHERE u.userDeleted = false")
List<USERS> findNotDeletedUsers();
and then call usersRepository.findNotDeletedUsers();
First of all, use an index on the field you want to search on (this won't help you much if the column has only two distinct values, but will make a huge difference if the value has high sparsity).
#Entity
#Table(name = "USERS",
indexes = {
// not a huge performance gain, since the column values are true/false
#Index(name = "index_by_active", columnList="ISDeleted", unique = false),
// possible huge performance gain, since only the relevant records are scanned
#Index(name = "index_by_first_name", columnList="FName", unique = false)})
public class USERS {...}
Then, define a query method that uses the indexed field (if you are using spring data it would look as follows).
public interface UsersRepository extends CrudRepository<USERS, Long> {
List<USERS> findUsersByISDeleted(boolean deleted);
List<USERS> findUsersByFName(String name);
List<USERS> findUsersByFNameAndISDeleted(String name, boolean deleted);
}
Queries on indexed fields will leverage the underlying index and provide an efficient access plan (so you won't end up scanning the whole table in order to extract a subset of entities matching a given criteria).
The solution from #Madis is okay. But if you always want to get users which are not deleted in all queries, you can specify it on Entity:
#Entity
#Table(name = "USERS")
#Where("ISDeleted = false")
public class USERS {
So now the condition "ISDeleted = false" is automatically append to all queries from the UserRepository. You can use usersRepository.findAll() instead of.
You don't need to specify any sql query or where clause. CrudRepository will do it for you automatically. Just use below code and pass true/false on need basis
List<Users> findIsUserDeleted(boolean isDeleted)
I'm working on saving schedule for shop into the db.
public class Shop {
#Id
private long id;
}
public class Schedule {
#Id
private long id;
#Column
#Enumerated(EnumType.STRING)
private DayOfWeek weekday;
#Column(name="time_from")
private Time from;
#Column(name="time_to")
private Time to;
#ManyToOne
#JoinColumn(name="shop_id")
private Shop shop;
}
What I want, is to have schedule available within Shop instance (one shop can have multiple to and from times, for example 09:00-13:00, 14:00-18:00), like this
public class Shop {
#Id
private long id;
private Map<DayOfWeek, List<Schedule>> scheduleList = new HashMap<>();
}
but I don't know how to map that. I was looking through the JPA 2.1 wiki page (https://en.wikibooks.org/wiki/Java_Persistence/Relationships#Nested_Collections.2C_Maps_and_Matrices), but the the criteria field is ENUM, and I think that there is no reason to create an extra table with 7 rows (for each weekday). Does anyone work with such features?
EDIT: the possible solution is to divide weekday to separate table:
Table shop
id
Table week_day
id
name
shop_id
Table hours
id
time_from
time_to
week_day_id
In this case the example from wiki would work, but is there any solution to use instead of intermediate table just enums?
If you used Java 8, then you could go with accessing the schedules on the shops with a simple inverse OneToMany relationship in your Shop object
#OneToMany
private List<Schedule> scheduleList;
and then creating a method like
public Map<DayOfWeek, List<Schedule>> getScheduleListByDaysOfWeek() {
return scheduleList.stream()
.collect(Collectors.groupingBy(Schedule::getWeekday);
}
I have 2 diferent Entities:
USER:
#Entity
public class UserMW {
#Id
private Long id;
private String name;
private Long score;
...
}
USER_CHALLENGE
#Entity
public class UserChallengeMW {
#Id
private Long id;
#Index
private Ref<UserMW> user;
#Index
#Load
private Ref<ChallengeMW> challenge;
}
I want to be able to get one ChallengeMW object and query all users which have done this ChallengeMW. So far it's pretty simple. I just need to query USER_CHALLENGE filtering by "Ref challenge". Something like this:
ofy().load().type(UserChallengeMW.class).filter("challenge", challengeRef).list();
The problem is, I want to order it according to the property "score" into USER entity. Any idea about what is the correct way to go?
Unfortunately, there are no joins in the datastore. Either denormalize the 'score' into the UserChallengeMW object or query for all the data and sort it in memory.
We have a Spring Boot/Data-JPA (1.3.3.RELEASE) application using Hibernate implementation where a CSV file is read and inserted into a database table called FIRE_CSV_UPLOAD. For records that are already present we just update them.
We retrieve record ID by querying for unique key (a combination of three columns) but this approach is inefficient for thousands of record in CSV file.
My question is how to update record without querying the table for unique key? If I do not query for ID then the record will be inserted instead of update.
I know one way which is to retrieve all records and store their unique key and ID pairs in a Map. Any other suggestions are very much appreciated. The codes are as below,
Note: They are minimized for brevity.
#Entity
#Table(name = "FIRE_CSV_UPLOAD",
uniqueConstraints={#UniqueConstraint(columnNames = {"account_number" , "account_type", "bank_client_id"})})
public class FireCsv {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#NotNull
#Column(name="account_number")
private String accountNumber;
#NotNull
#Column(name="account_type")
private String accountType;
#NotNull
#Column(name="bank_client_id")
private String bankClientIdNumber;
...
other fields/getters/setters
}
--
public interface FireCsvRepository extends JpaRepository<FireCsv, Long> {
#Query("select u from FireCsv u where u.accountNumber = :accountNumber and u.accountType = :accountType and u.bankClientIdNumber = :bankClientIdNumber ")
FireCsv findRecord(#Param("accountNumber") String accountNumber,
#Param("accountType") String accountType,
#Param("bankClientIdNumber") String bankClientIdNumber);
}
--
#Service
public class FireCsvServiceImpl implements FireCsvService {
other fields/methods
...
#Override
#Transactional
public FireCsv save(final FireCsv fireCsv) {
FireCsv existingFireCsv = fireCsvRepository.findRecord(fireCsv.getAccountNumber(), fireCsv.getAccountType(), fireCsv.getBankClientIdNumber());
// If record exist then mark as update, if not as insert
if (existingFireCsv != null) {
fireCsv.setId(existingFireCsv.getId());
fireCsv.setRecordStatus(CSVUploadRecordStatus.CSV_UPDATE.getStatus());
}
else {
fireCsv.setRecordStatus(CSVUploadRecordStatus.CSV_INSERT.getStatus());
}
fireCsv.setRecordStatusDate(new java.sql.Timestamp(new Date().getTime()));
return fireCsvRepository.save(fireCsv);
}
}
You have to read before deciding to make an update or insert, I dont think there is a way around it.
To make that faster you should add an index to your database
using the three columns "account_number", "account_type", "bank_client_id".
Alternatively you can try to use an composite id using #IdClass as shown in
tutorial-jpa-composite-primary-key
The JPA provider should than automatically create the index for it.