I am new to Android Room Database.
I saw there have similar questions on that topic, but i really didn't understand what actually worked for this topic.
So, here I am trying to get the first date from the table, but while I query with that
#Query("select min(date) from user_items where userId = :userId ")
long getFirstDate(long userId);
I got the result as a minimum date is 01/01/1970
But i want the first date from the table to show the user.
My entity class User.java:
#Entity(tableName = "users")
public class User {
#PrimaryKey(autoGenerate = true)
private int id;
private String name;
private String email;
private String password;
private String securityAnswer;
// other staff here
}
My another entity has a relation with User table.
UserItem.java:
#Entity(tableName = "user_items", indices = {#Index("userId")}, foreignKeys = #ForeignKey(entity = User.class,
parentColumns = "id",
childColumns = "userId",
onDelete = CASCADE))
public class UserItems {
#PrimaryKey(autoGenerate = true)
private int id;
private String category;
private String amount;
private String date;
#ColumnInfo(name = "userId")
private int userId;
// setter and getter
}
My other all query worked fine except min(date) function.
This is my entity, i want the first date as i marked, to show the user
Finally I got the solution:
Here I change my query
Instead of this:
#Query("select min(date) from user_items where userId = :userId ")
long getFirstDate(long userId);
Use this:
#Query("select min(date) from user_items where userId = :userId ")
String getFirstDate(long userId);
Because if you look my UserItem.java class , here i am storing data as String
so, if i want to store String to the long type, it's not allowed.
Hope it will help you.
The query is returning the start of the UNIX epoch (01/01/1970) which indicates that you might have persisted (or attempted to persist) an invalid value in the date column for one of your rows. You might want to check for any suspicious values in the date column.
Related
I'm trying to fetch all rows that have the same patient_id, so I'm doing findAllByPatientId. But I'm always receiving one object in the Listinstead of all the rows.
#Entity
#Getter
#Setter
public class MedicalHistory extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name = "operator_id")
private MedicalOperator medicalOperatorId;
#ManyToOne
#JoinColumn(name = "illness_id")
private Illness illnessId;
#ManyToOne
#JoinColumn(name= "patientId")
private Patient patientId;
}
public List<MedicalHistory> getPatientMedicalRecords(PatientDto patientDto) {
Optional<Patient> getPatient = patientRepository.findByNin(patientDto.getNin());
Long patientId = getPatient.get().getPatientId();
return medicalHistoryRepository.findAllByPatientId(patientId);
}
I want to receive multiple rows using the patient_id but instead, I'm always getting one !!.
I tried native query and hibernate but nothing is working.
public interface MedicalHistoryRepository extends JpaRepository<MedicalHistory, Long> {
// List<MedicalHistory> findAllByPatientId(Long id);
ArrayList<MedicalHistory> findMedicalHistoriesByPatientId(Long id);
#Query(value = "SELECT * FROM medical_history WHERE patient_id = id",nativeQuery = true)
List<MedicalHistory> findAllByPatientId(Long id);
}
Now you are requesting "give me medical_history where id = patient_id" and getting only one result row.
You need to add a colon to the query to set a parameter to fix a result
value = "SELECT * FROM medical_history WHERE patient_id = :id"
Look for JPQL, it's java persistancy query language and spring is automatically turning your #query into it. Spring is also supporting spEL you can also have a look to it here : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query.spel-expressions where you can see than you can grab your parameters ever with ?number or with :name or putting #Param("name") into your parameters definition. As said before there is multiple ways to receive a parameter in you query but certainly not like you previously did.
That's why you don't receive anything.
I am developping a chat app. I have two Entities
#Entity(tableName = "messages")
public class MessageItem {
#PrimaryKey
private Integer msgId;
#ColumnInfo(name = "from_id")
private String contact_id;
}
And
#Entity(tableName = "contact")
public class Contact{
#PrimaryKey
private Integer id;
#ColumnInfo(name = "contact_phone")
private String phone;
}
In MessageDao I want to get Contact phone correponding to the contact_id in MessageItem
You have three ways you can do this.
1) You can use a POJO with an #Embedded and an #Relation in which case you return MessageItem's with the Contact e.g. :-
public class MessageItemWithContact {
#Embedded
MessageItem messageItem;
#Relation(entity = Contact.class, parentColumn = "from_id", entityColumn = "id")
Contact contact;
}
along with an #Query such as :-
#Transaction
#Query("SELECT * FROM messages WHERE msgId=:msgId")
MessageItemWithContact getMessageByIdWithContact(int msgId);
2) Or you can use a POJO with an #Embedded and an additional variable for the phone using a JOIN e.g. :-
public class MessageItemWithPhone {
#Embedded
MessageItem messageItem;
String phone;
}
Along with an #Query like :-
#Query("SELECT msgId, contact_phone, from_id FROM messages JOIN contact On from_id = id ")
List<MessageItemWithPhone> getMessItemWithContactPhone();
doesn't need #Transaction as the query is a single transaction (whilst the previous method Room obtains the MessageItem and then builds a query to get the related object(s)).
this query gets all MessageItems (as no WHERE clause has been included)
3) Just get the phone using the from_Id for the relevant MessageItem without the need for a POJO by having an #Query like:-
#Query("SELECT contact_phone FROM contact WHERE id=:from_Id")
String getPhoneById(String from_Id);
We have a deleted column on our table, is it possible to check that every time this table is queried the query has a condition for this column?
Some googling with better keywords (soft-delete) it seems I could do this with #When annotation. not exactly what I was looking but seems close enough.
You can check out #Where annotation.
org.hibernate.annotations.Where
Example:
If there's an Account Entity
#Entity(name = "Account")
#Where( clause = "active = true" )
public static class Account {
#Id
private Long id;
#ManyToOne
private Client client;
#Column(name = "account_type")
#Enumerated(EnumType.STRING)
private AccountType type;
private Double amount;
private Double rate;
private boolean active;
//Getters and setters omitted for brevity
}
and if the following code is used for fetching the accounts.
List<Account> accounts = entityManager.createQuery(
"select a from Account a", Account.class)
.getResultList();
then the following SQL will be generated
SELECT
a.id as id1_0_,
a.active as active2_0_,
a.amount as amount3_0_,
a.client_id as client_i6_0_,
a.rate as rate4_0_,
a.account_type as account_5_0_
FROM
Account a
WHERE ( a.active = true )
Hibernate ORM 5.2.18.Final User Guide
I have two entities, simplified for the case. The isActive field changes with current time so i did not want to store it in db.
Condition of isactive:
isActive = 1 if (current_timestamp between userstatus.datebegin and userstatus.dateend) else isActive = 0
What I want:
I want to get a set of ALL users, with their isActive values set without hitting to the db for every user and preferably; without userStatus collection carried around. Is there a way to satify this programmatically or jpa way? Or what is the best way to achieve this?
User.java:
#Entity
public class User {
#Id
private long id;
#Transient
private int isActive;
#OneToMany(mappedBy = "user",fetch = FetchType.LAZY)
private Set<UserStatus> userStatus = new HashSet<>();
}
UserStatus.java:
public class UserStatus {
#Id
private long id;
#Column
private Date dateBegin;
#Column
private Date dateEnd;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name= "user_tr_id_no")
private UmutUser user;
}
UserRepository.java:
#Repository
public interface UserRepository extends JpaRepository<User, long> {
Set<User> findAllFetchWithIsActive();
}
Ways I tried:
*Way1: PostLoad
Problem: If I dont fetch userStatus, it hits the db for every user object.
*Way2: JPQL Query:
Problem: Couldnt find a query to set transient value except something suggested in here. The problem is it hits the db for every user object again.
*Way3: Eagerly fetch userStatus, calculate isActive values in service, hide the set of userstatus in a DTO before passing around.
Problem: This is my last resort, I have doubts fetching userStatus set for ALL users is a good approach.
I think the best approach would be something like this:
#Query("SELECT e FROM User u WHERE u.userStatus.dateBegin < CURRENT_DATE AND u.userStatus.dateEnd > CURRENT_DATE")
Iterable<User> findAllActiveUsers();
And in your User class
#Entity
public class User {
#Id
private long id;
#OneToMany(mappedBy = "user",fetch = FetchType.LAZY)
private Set<UserStatus> userStatus = new HashSet<>();
#Transient
public int isActive(){
for(UserStatus status: userStatus) {
//Add your logic to check if the current date is between the range
}
}
}
You may want to use the new operator:
select new UserWithStatus(
u,
u.userStatus.dateBegin < CURRENT_DATE AND u.userStatus.dateEnd > CURRENT_DATE)
from User u
And have your object UserWithStatus:
public class UserWithStatus {
private User user;
private boolean active;
public UserWithStatus(User user, boolean active) {
this.user = user;
this.active = active;
}
}
And have this in your repository:
#Query("...")
Set<UserWithStatus> findAllFetchWithIsActive();
Note: I think this will bring you duplicate (eg: one User with several status). You might need to use a subquery and I don't know if JPQL will allow you this:
select new UserWithStatus(u,
(select count(*)
from u.userStatus w
where w.dateBegin < CURRENT_DATE
and w.dateEnd > CURRENT_DATE)) > 0
from User u
Envrionment: Java, Hibernate JPA provider, JPA, Oracle DB
I am trying to create a native query to fetch the data from the Oracle DB. One of the columns is a date column. The date is fetched, but the timestamp is coming out as 00:00:00. However, through an SQL browser, I can see the date and the time. How do I fetch the resultList along with the time?
org.hibernate.Query query = ((HibernateEntityManager) entityManager).getSession().
createSQLQuery(NATIVE_QUERY).setResultTransformer(org.hibernate.transform.Transformers.ALIAS_TO_ENTITY_MAP);
query.setString(0, accountNumber);;
query.setTimestamp(1, startDate).setTimestamp(2, endTime);
query.setTimestamp(3, startDate).setTimestamp(4,endTime);
List resultList = query.list();
The query itself (in the code above - NATIVE_QUERY) is a normal SQL query for - "Get me all user names and txn time within a given date range whether it is a new transaction or something that has changed in some form".
select u.first_name as firstName, u.last_name as lastName, tx.start_time as txnTime from user u, transaction tx where tx.user_id=u.user_id and tx.account_number=? and (tx.start_time > ? and tx.start_time < ? or tx.change_time > ? and tx.change_time < ?)
for(Object listItem : resultList){
Map map = (Map) listItem;
Date txnTime = (Date)map.get("txnTime".toUpperCase());
//--------> NOT FETCHING THE TIME. I get the time as 00:00:00
}
The domain model is very simple
#Entity
#Table(name="TRANSACTION")
#org.hibernate.annotations.Entity(
dynamicUpdate = true
)
public class Transaction{
#Id
#SequenceGenerator(name="txn_gen", sequenceName="TXN_S")
#GeneratedValue(generator="txn_gen")
#Column(name="TXN_ID")
private Long txnId;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="USER_ID", nullable=false)
private User user;
#Column(name="START_TIME", nullable=false)
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date startTime;
#Column(name="CHANGE_TIME")
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date changeTime;
}
#Entity
#Table(name="USER")
#org.hibernate.annotations.Entity(
dynamicUpdate = true
)
public class User {
#Id
#SequenceGenerator(name = "user_gen", sequenceName = "USER_S")
#GeneratedValue(generator = "user_gen")
#Column(name="USER_ID")
private Long userId;
#Column(length=500, name="FIRST_NAME")
private String firstName;
#Column(length=500, name="LAST_NAME")
private String lastName;
}