I have 5 different tables in my database on MS SQL Server 2012. I have created class for my UserTable and filled in setters and getters shown below , is it logical to put other tables's setters and getters inside the same glass or create separate class for other tables with setters and getters.
import java.math.BigDecimal;
import java.sql.Connection;
public class UserFR17setget {
Connection cn;
BigDecimal userID;
String UserName;
String UserPassword;
int UserSecurity;
BigDecimal ProjectID;
public BigDecimal getUserID() {
return userID;
}
public void setUserID(BigDecimal userID) {
this.userID = userID;
}
public String getUserName() {
return UserName;
}
public void setUserName(String UserName) {
this.UserName = UserName;
}
public String getUserPassword() {
return UserPassword;
}
public void setUserPassword(String UserPassword) {
this.UserPassword = UserPassword;
}
public int getUserSecurity() {
return UserSecurity;
}
public void setUserSecurity(int UserSecurity) {
this.UserSecurity = UserSecurity;
}
public BigDecimal getProjectID() {
return ProjectID;
}
public void setProjectID(BigDecimal ProjectID) {
this.ProjectID = ProjectID;
}
}
Regards
You're basically implementing a part of JPA yourself. In JPA a class maps to a database table, and you think in terms of entities instead of database tables. You might want to explore that later on (unless you wish to do so now).
If you just want to map database data into objects, you have a few reasonable choices. Do as you're doing now, make each database table have a related class (User is a lot better name for a class than UserFR17getset by the way), then you can manipulate the data as objects. A more higher level approach is to have the classes reference to other tables, so your User class would contain an Address reference (assuming there's a table Address), and when loading a User, it would also load the Address. This is similar to how JPA works, and then you would be able to do a single "load user 1" instead of "load user 1, load address for user 1". Of course you would be responsible for implementing the actual loading (unlike with JPA, where there's a lot of automation going on).
Don't make the Connection object a part of your class though, it has no business being there. You should use the Connection object with your loading method, such as User u = loadUser(connection, userId);
Related
I am following a Udemy tutorial in Spring boot. There's a part where #Query wasn't used for a user-created method in the repository interface. It works, but I want to understand when JpaRepository takes care of the creation of query. In the User class below, #Table wasn't used.
findByEmail(String email) method works without any implementation/definition. So, my impression was that, JpaRepository automatically created the Select from User where email = emailargument
So here's what I have
A database named reservation with table User
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/reservation
spring.datasource.username=root
User.java
import javax.persistence.Entity;
#Entity
public class User extends AbstractEntity{
private String firstName;
private String lastName;
private String email;
private String password;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import com.project.flightreservation.entities.User;
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
}
When Spring Data creates a new Repository implementation, it analyses all the methods defined by the interfaces and tries to automatically generate queries from the method names. While this has some limitations, it's a very powerful and elegant way of defining new custom access methods with very little effort. Ref
by implementing one of the Repository interfaces, the DAO will already have some basic CRUD methods (and queries) defined and implemented.
You can create more complex queries with this approach reference
The one which you posted in question is called automatic custom query.
JPA has ability to construct query in different ways. You can use queries derived from methodName with the predicates IsStartingWith, StartingWith, StartsWith, IsEndingWith, EndingWith, EndsWith, IsNotContaining, NotContaining, NotContains, IsContaining, Containing, Contains the respective arguments for these queries will get sanitized.
If you face the situation in which either the method name parser does not support the keyword you want to use or the method name would get unnecessarily ugly, you can use #Query for namedQuery support of JPQL or nativeQuery.
I would strongly suggest you to go through this documentation
i am writing a web application(server based application) where i am having a dao layer, the service layer and the application layer. how should i take over the lazy initialization exception, caused due to the fact that entity returned from dao layer is concerned with the session opened inside the method from where it is returned and also closed there which makes the entity detached.
Next thing is it safe to share the hibernate entities across different layer. what makes me to ask this question is the scenario: for example suppose i am having a hibernate entity having one to one association with some other entity. and suppose dao passed it to the service layer to the application layer. now if i try to get this associated entity in application layer through the passed entity getter method, a database query is fired which i think is messing up with the "seperation of concerns" as database related operation should be constrained to the dao layer. am i right?
i have discovered the mentioned problem during the time i am unit testing my dao layer through in-memory database. My scenario is, i am having one of the pojo class called RegisteredUser having the fields: (id, username, firstname, lastname, passwHash, email, StudyCentre). StudyCentre is an another entity which is assosciated with RegistereUser by one to one mapping and username is the naturalid.
What i want is 2 types of read operation, first one is i need to get user details without studycentre through natural id and second one is getting the complete user fields again through naturalid. is making two seperate DTOs a good idea here and passing them across layers.
RegisteredUser Entity:
package com.ignoubadhega.pojos;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.NaturalId;
#Entity
#Table(name = "registered_user")
#DynamicUpdate
public class RegisteredUser {
private Long dbUserId;
private String userName;
private String passwHash;
private String firstName;
private String lastName;
private String email;
private StudyCentre studyCentre;
RegisteredUser() {
}
public RegisteredUser(
String userName, String passwHash, String firstName,
String lastName, String email
) {
super();
this.userName = userName;
this.passwHash = passwHash;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "db_user_id")
public Long getDbUserId() {
return dbUserId;
}
#Override
public String toString() {
return "RegisteredUser [dbUserId="
+ dbUserId
+ ", userName="
+ userName
+ ", passwHash="
+ passwHash
+ ", firstName="
+ firstName
+ ", lastName="
+ lastName
+ ", email="
+ email
+ "]";
}
public void setDbUserId(Long dbUserId) {
this.dbUserId = dbUserId;
}
#Column(name = "username", nullable = false, unique = true)
#NaturalId
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
#Column(name = "passw_hash", nullable = false)
public String getPasswHash() {
return passwHash;
}
public void setPasswHash(String passwHash) {
this.passwHash = passwHash;
}
#Column(name = "first_name", nullable = false)
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Column(name = "last_name", nullable = false)
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Column(name = "email", nullable = false, unique = true)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "db_study_centre_id", nullable = false)
public StudyCentre getStudyCentre() {
return studyCentre;
}
public void setStudyCentre(StudyCentre studyCentre) {
this.studyCentre = studyCentre;
}
}
Dao Implementor:
package com.ignoubadhega.dao.impl;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.ignoubadhega.dao.RegisteredUserDAO;
import com.ignoubadhega.pojos.RegisteredUser;
public class RegisteredUserDAOImpl implements RegisteredUserDAO {
private SessionFactory sessionFactory;
public RegisteredUserDAOImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Override
public void addUser(RegisteredUser user) {
try (Session session = sessionFactory
.openSession()) {
session.beginTransaction();
session.persist(user);
session.getTransaction().commit();
} catch (HibernateException except) {
except.printStackTrace();
}
}
#Override
public RegisteredUser getUserByUserName(String username, boolean doesStudyCentereNeeded) {
try (Session session = sessionFactory
.openSession()) {
RegisteredUser user = session
.bySimpleNaturalId(RegisteredUser.class).load(username);
if (doesStudyCentereNeeded) {
user.setStudyCentre(user.getStudyCentre());
}
return user;
} catch (HibernateException except) {
except.printStackTrace();
}
return null;
}
#Override
public void deleteUser(RegisteredUser user) {
try (Session session = sessionFactory
.openSession()) {
session.beginTransaction();
session.delete(user);
session.getTransaction().commit();
} catch (HibernateException except) {
except.printStackTrace();
}
}
#Override
public void updateUser(RegisteredUser user) {
try (Session session = sessionFactory
.openSession()) {
session.beginTransaction();
session.update(user);
session.getTransaction().commit();
} catch (HibernateException except) {
except.printStackTrace();
}
}
}
TestCase which finds the problem of lazy initalization:
#Test
#DisplayName(
"User through its natural id 'username' assuming the user"
+ " is persistent in the database is successful"
)
void test_fetching_a_persistent_user_through_username_is_successful() {
try (Session session = sessionFactory.openSession()) {
session.beginTransaction();
session.persist(user);
session.getTransaction().commit();
RegisteredUser retrievedUser =
dao.getUserByUserName("prav", true);
assertNotNull(retrievedUser);
assert_actual_user_and_retrieved_user_fields_are_equal(user,
retrievedUser);
} catch (HibernateException except) {
except.printStackTrace();
}
}
private static void assert_actual_user_and_retrieved_user_fields_are_equal(
RegisteredUser actualUser, RegisteredUser userRetrieved
) throws MultipleFailuresError {
assertAll("user fields",
() -> assertEquals(actualUser.getUserName(),
userRetrieved.getUserName()),
() -> assertEquals(actualUser.getPasswHash(),
userRetrieved.getPasswHash()),
() -> assertEquals(actualUser.getFirstName(),
userRetrieved.getFirstName()),
() -> assertEquals(actualUser.getLastName(),
userRetrieved.getLastName()),
() -> assertEquals(actualUser.getEmail(),
userRetrieved.getEmail()),
() -> {
StudyCentre retrievedCentre =
userRetrieved.getStudyCentre();
assertNotNull(retrievedCentre);
assertAll("user study centre assosciated",
() -> assertEquals(
actualUser.getStudyCentre().getData()
.getStudyCentreName(),
retrievedCentre.getData()
.getStudyCentreName()),
() -> assertEquals(
actualUser.getStudyCentre().getData()
.getRegionalCentreCode(),
retrievedCentre.getData()
.getRegionalCentreCode()));
});
}
i want to keep my service layer(not yet implemented) to be isolated from things specific to hibernate like sessions and database related operations(CRUD). how can i achieve it. is there any design patterns i should follow. i am new to hibernate. please guide me if i am doing something wrong any where. i have tried finding the similar threads on google but failed to get any insights about the issue.
how should i take over the lazy initialization exception, caused due to the fact that entity returned from dao layer is concerned with the session opened inside the method from where it is returned and also closed there which makes the entity detached.
You would deal with that by opening and closing the session in the service or the application layer, and doing all the work in a single transaction.
is it safe to share the hibernate entities across different layer
Yes. What is not safe is to use an entity instance across several threads, because entities are not thread-safe.
a database query is fired which i think is messing up with the "seperation of concerns" as database related operation should be constrained to the dao layer. am i right?
No. The service layer doesn't contain any code to trigger this database query. It happens transparently, without the service layer having to care about it, and because you chose to make the association lazy.
is making two seperate DTOs a good idea here and passing them across layers.
No. DTOs are useful to transfer data between separate applications. Inside your application, working with managed entities is the correct way.
i want to keep my service layer(not yet implemented) to be isolated from things specific to hibernate like sessions and database related operations(CRUD). how can i achieve it.
By using Spring or Java EE (or any other framework that has this feature) which allow using declarative transactions and deal with the task of opening/closing sessions and transactions for you whenever a transactional method is called.
You should also avoid using the proprietary Session API, and use the standard JPA API instead.
I was going through some tutorials on Hibernate, and I came across one scenario in which a primary key can be a compound (like 2-3 fields taken together form primary key). As per my understanding, this is achievable using #EmbeddedId annotation.
I tried to do this using simple application.
UserObj Object:
package com.vipin.model;
import javax.persistence.Embeddable;
#Embeddable
public class UserObj {
private int userId;
private String userName;
private String SSN;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSSN() {
return SSN;
}
public void setSSN(String sSN) {
SSN = sSN;
}
}
****UPDATE*****
UserModel which uses UserObj as Compound primary key:
#Entity(name="USER_DETAILS")
public class UserModel implements Serializable {
#EmbeddedId
private UserObj userObj;
#Id
#Column(name="USER_ID")
#GeneratedValue(strategy=GenerationType.SEQUENCE)
private int userId;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public UserObj getUserObj() {
return userObj;
}
public void setUserObj(UserObj userObj) {
this.userObj = userObj;
}
Main application/ demo application:
package com.vipin.mainapplication;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.vipin.model.UserModel;
import com.vipin.model.UserObj;
public class HibernateMain {
public static void main(String[] args) {
UserModel userModel = new UserModel();
UserObj userObj = new UserObj(); //Demo of Primary key which is an object.
userObj.setUserId(1);
userObj.setUserName("VIPIN KOUL");
userObj.setSSN("000001");
userModel.setUserObj(userObj); //Demo of Primary key which is an object.
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(userModel);
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
}
However when I run this program, i am able to save the data into DB, even though i supply the same values for all these fields. With #EmbeddedId, isn't hibernated supposed to check that it doesn't allow to save this object into DB if same object exists in DB (i.e. duplicate values not allowed).
Do we need to enforce anything on DB side as well? I am under the impression that this annotation is going to check.
Any clues greatly appreciated.
***UPDATE****
I missed to include one more piece of code in UserModel:
#Id
#Column(name="USER_ID")
#GeneratedValue(strategy=GenerationType.SEQUENCE)
private int userId;
With this, hibernate was taking the combination of these four coloumns as primary key, and so no exception.
I removed this field and when i run the program second time (with same values), it throw the exception.
Hence, in conclusion #EmbeddedId does enforce primary key in case we have compound primary key.
Assume a model named User:
#Entity
public class User extends Model {
#Id
#Constraints.Min(10)
public Long id;
#Constraints.Required
public String username;
#Constraints.Required
public String password;
public static Finder<Long, User> find = new Finder<Long, User>(
Long.class, User.class
);
}
When I attempt to update an instance of User in my controller:
User user = User.find.where().eq("username", username).findUnique();
if(user != null) {
user.username = "some_new_username";
user.save();
}
no changes seem to be committed. I read somewhere that when you alter a model instance by its property, it does not get dirty and therefore no changes take place. Hence you should use a setter instead. In the documentation of Play Framework it is said that those setters (and getters) are generated automatically, but using user.setUsername(username) gives me a compilation error:
cannot find symbol [symbol: method setUsername(java.lang.String)] [location: class models.User]
Am I missing something?
Have you tried adding custom setters?
#Entity
public class User extends Model {
#Id
#Constraints.Min(10)
public Long id;
#Constraints.Required
public String username;
public void setUsername(String _username) {
username = _username;
}
#Constraints.Required
public String password;
public void setPassword(String _password) {
password = _password;
}
public static Finder<Long, User> find = new Finder<Long, User>(
Long.class, User.class
);
}
As far as I can tell, automatic getter/setter translation is broken in Play2. Your assignment:
user.username = "some_new_username";
should have triggered the function call:
user.setUsername("some_new_username");
This translation seems to be broken in Play 2. Here's my own question on the subject.
Hypothetically, lets say I have a domain object called Person. It looks like such:
public class Member {
private final String firstName;
private final String lastName;
private final String email;
private final String password;
public Member(String firstName, String lastName, String email, String password) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
}
I also have a MemberRepository interface that defines basic CRUD and some other sugary methods.
Now lets say I want to persist this domain object in a MongoDB instance using Morphia. I've created my MorphiaMemberRepository implementation but what I'm unsure of is how to store the domain object with as little mess as possible.
Any Morphia users would know that I'd need to create an ID field of type ObjectId and annotate it with #Id. Additionally I'd need to annotate the class with #Entity("members"). I don't necessarily want to clutter up my nice domain object with the Morphia/MongoDB specific annotations.
So...fellow stackers, what should I do to keep this implementation as clean as possible?
That is the requirement for Morphia (at least the #Id one). Annotations do not require changing the way you use your object or serialization. They are just extra metadata which most programs ignore; they are harmless.
If you have a unique field then you don't need to add any new ones, just mark that with #Id and be done with it.
If you really don't want to do any of this, you can manually create the metadata in morphia to deal with your classes, but that will be much more work as that process is not exposed via any external configuration format.
Suppose there is IMember so Member implements IMember. Getter methods are defined in IMember.
Another class MorphiaMember implements IMember is annotated as necessary and has ID field (id is not always ObjectId).
Each class has a factory method
public static Member from(IMember mi) { ... }
so typical workflow will be:
MemberRepository repo = ...
Member m = Member.from(repo.get(some_id))
...
Member m2 = ...
repo.save(MorphiaMember.from(m))