I have three bean classes: Users ,UserDetail and Auth and i am doing in service class
#Override
public void addUser(UserDetail userDetail) {
Users users=new Users();
users.setUsername(userDetail.getUsername());
users.setEnabled(userDetail.isEnabled());
users.setAgentId(userDetail.getAgentId());
Auth auth = new Auth();
auth.setUsername(userDetail.getUsername());
auth.setAuthority(userDetail.getAuthority());
userDetailDao.addUser(userDetail, users, auth);
}
and i want to save these all object in Dao class like
#Override
public void addUser(UserDetail userDetail,Users users,Auth auth)
{
// TODO Auto-generated method stub
getSession().saveOrUpdate(userDetail);
//Here i also want to save 'users' and 'auth' in same transaction..
getSession().flush();
}
Can it possible to solve you can try it...Thanks.
If you reconstruct your UserDetail class to something like this:
public final class UserDetail
{
private Users user;
private Auth auth;
// Getter and Setter
}
You can just go ahead and store the UserDetail object via Hibernate in the Database.
Of course you need to add the required annotations to the UserDetail class.
Alternativly don't reconstruct UserDetail but create a new class to store both objects in, something like UserDetailDO or UserDetailPersistence or some better name you can totally come up with by yourself.
Just take care with the annotations to set up the relations correctly, like OneToOne or OneToMany.
In your case UserDetail class reference members is used in Users and Auth class, and it can be mapped based on primary key of either UserDetail class or Users class.
So you can re-define those secondary classes(Users and Auth) based on primary key referense of UserDetail class instead of creating objects each time.
Take care of annotations of foreign key references.
Other way of doing this to define base details in a class and extend that class to secondary classes. But most scenarios doesn't work with this approach as the object is created again and again which may have application performance.
The problem is manage your transaction in DAO, the best way is your business layer manage the transaction.
Like this:
class BO {
doSomething() {
DaoA daoA = new DaoA();
DaoB daoB = new DaoB();
transaction.begin();
daoA.insert();
daoB.insert();
transaction.commit();
}
}
See this post too:
Where should "#Transactional" be place Service Layer or DAO
Related
In my microservice written on spring-boot I have following DTO and Entity:
#Entity
class Order {
#Id
private Long id;
#OneToMany
private List<Product> products;
// getters setters
public Product getMainProduct() {
final String someBusinessValue = "A";
return products.stream()
.filter(product -> someBusinessValue.equals(product.getSomeBusinessValue()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No product found with someBusinessValue 'A'"));
}
}
class OrderRequest {
private List<ProductDto> productDtos;
// getters setters
public ProductDto getMainProductDto() {
final String someBusinessValue = "A";
return productDtos.stream()
.filter(productDto -> someBusinessValue.equals(productDto.getSomeBusinessValue()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No productDto found with someBusinessValue 'A'"));
}
}
As seen both entity and dto contain some business logic method for taking the "main" product from the list of all product. It is needed to work with this "main" product in many parts of the code (only in service layer). I have received a comment after adding these methods:
Design-wise you made it (in Dto) and the one in DB entity tightly coupled through all layers. This method is used in services only. That means that general architecture rules for layers must apply. In this particular case, the "separation-of-concerns" rule. Essentially it means that the service layer does not need to know about the request parameter of the controller, as well as the controller shouldn't be coupled with what's returned from service layer. Otherwise a tight coupling occurs. Here's a schematical example of how it should be:
class RestController {
#Autowired
private ItemService itemService;
public CreateItemResponse createItem(CreateItemRequest request) {
CreateItemDTO createItemDTO = toCreateItemDTO(request);
ItemDTO itemDTO = itemService.createItem(createItemDTO);
return toResponse(itemDTO);
}
In fact, it is proposed to create another intermediate DTO (OrderDto), which additionally contains the main product field:
class OrderDto {
private List<ProductDto> productDtos;
private ProductDto mainProductDto;
// getters setters
}
into which the OrderRequest will be converted in the controller before passing it to the service layer, and the OrderEntity already in the service layer itself before working with it. And the method for obtaining the main product should be placed in mapper. Schematically looks like this:
---OrderRequest---> Controller(convert to OrderDto)
---OrderDto--> Service(Convert OrderEntity to OrderDto) <---OrderEntity--- JpaRepository
Actually, this leads to a lot of additional conversions within the service, some unusual work, for example, when updating an entity, now you have two intermediate dto (one from the controller for the update), the other from the repository (the entity found for the update and converted to intermediate dto in service layer) and you need to adopt the state of one into the other, and then map the result to the entity and do update.
In addition, it takes a lot of time to refactor the entire microservice.
The question is, is it a bad approach to have such methods in the entity and incoming dto, though these methods are used only in service layer, and is there another approach to refactor this?
If you need any clarification please let me now, thank you in advance!
In my application, I am fetching customer details from an API and saving this customer to the database. after saving this customer object to in my database, I am returning customer object with id generated by the database.
this is my rest Controller layer for getting customer object from API.
//add a new customer and then return all details of newly created customer
#PostMapping("/customer")
public Customer addCustomer(#RequestBody Customer theCustomer)
{
// also just in case they pass an id in JSON ... set id to 0
// this is to force a save of new item ... instead of update
theCustomer.setId(0);
return theCustomerService.saveCustomer(theCustomer);
}
this is my service layer
#Service
public class CustomerServiceImpl implements CustomerService {
private CustomerDAO theCustomerDAO;
// set up constructor injection
#Autowired
public CustomerServiceImpl(CustomerDAO theCustomerDAO)
{
this.theCustomerDAO=theCustomerDAO;
}
#Override
#Transactional
public Customer saveCustomer(Customer thCustomer) {
return theCustomerDAO.saveCustomer(thCustomer);
}
}
and this my CustomerDAO layer where I am saving it to database
public Customer saveCustomer(Customer theCustomer)
{
// get the current hibernate session
Session currentSession = entityManager.unwrap(Session.class);
//save the customer
currentSession.saveOrUpdate(theCustomer);
return theCustomer;
}
above parts of my Application are working properly but now I want to add testing in it.
so I created a test method for the service layer.
class CustomerServiceImplTest {
#Test
void saveCustomer() {
CustomerDAO theCustomerDAO=mock(CustomerDAO.class);
CustomerServiceImpl theCustomerServiceImpl=new CustomerServiceImpl(theCustomerDAO);
Customer inCustomer=new Customer("john","nick","google#gmail.com","CPOI939","8607574640");
inCustomer.setId(0);
Customer outCustomer=inCustomer;
outCustomer.setId(9);
when(theCustomerDAO.saveCustomer(inCustomer)).thenReturn(outCustomer);
assertEquals(outCustomer,theCustomerServiceImpl.saveCustomer(inCustomer));
}
}
But I am not sure that it's a good way of testing because we are not adding any business logic in the service layer.
so how do I test it and which layer should be tested.
Try to test this case on the integration level. There is no business logic just pure crud to save data to DB.
You can use DbUnit and in-memory databases like H2.
DbUnit is a JUnit extension targeted at
database-driven projects that, among other things, puts your database
into a known state between test runs.
example test:
#Test
#DatabaseSetup("sampleData.xml")
public void testSaveCustomer() throws Exception {
Customer inCustomer=new Customer("john","nick","google#gmail.com","CPOI939","8607574640");
theCustomerServiceImpl.saveCustomer(inCustomer)
List<Customer> customerList = customerService.findAll();
assertEquals(1, customerList.size());
assertEquals("john", customerList.get(0).getName());
...
}
More details Spring nad DBUnit
Hello everyone I'm new to Spring world. Actually I want to know how can we use converter to update object instead of updating each element one by one using set and get. Right now in my controller I've :
#PostMapping("/edit/{userId}")
public Customer updateCustomer(#RequestBody Customer newCustomer, #PathVariable final String userId)
{
return customerService.update(userId, newCustomer);
}
and this is how I'm updating the customer object :
#Override
public Customer update(String id, Customer newCustomer) {
Customer customer = customerRepository.findById(id).get();
customer.setFirstName(newCustomer.getFirstName());
customer.setLastName(newCustomer.getLastName());
customer.setEmail(newCustomer.getEmail());
return customerRepository.save(customer);
}
Instead of using each time set and get, I want to use a converter.
The approach of passing the entity's id as a path variable when you're updating it isn't really right. Think about this: you have a #RequestBody, why don't you include the id inside this body too? Why do you want to specify a path variable for it?
Now, if you have the full Customer with its id from the body, you don't have to make any calls to your repository because hibernate adds it to a persistent state already based on its id and a simple
public Customer update(Customer newCustomer) {
return customerRepository.save(newCustomer);
}
should work.
Q: What is a persistent state?
A: A persistent entity has been associated with a database table row and it’s being managed by the current running Persistence Context. ( customerRepository.findById() is just asking the DB if the entity with the specified id exists and add it to a persistent state. Hibernate manage all this process if you have an #Id annotated field and is filled, in other words:
Customer customer = new Customer();
customer.setId(1);
is ALMOST the same thing as :
Customer customer = customerRepository.findById(1).get();
)
TIPS: Anyway, you shouldn't have (if you didn't know) a model in the controller layer. Why? Let's say that your Customer model can have multiple permissions. One possible structure could look like this:
#Entity
public class Customer{
//private fields here;
#OneToMany(mappedBy="customer",--other configs here--)
private List<Permission> permissions;
}
and
#Entity
public class Permission{
#Id
private Long id;
private String name;
private String creationDate;
#ManyToOne(--configs here--)
private Customer customer;
}
You can see that you have a cross reference between Customer and Permission entity which will eventually lead to a stack overflow exception (if you don't understand this, you can think about a recursive function which doesn't have a condition to stop and it's called over and over again => stack overflow. The same thing is happening here).
What can you do? Creating a so called DTO class that you want the client to receive instead of a model. How can you create this DTO? Think about what the user NEEDS to know.
1) Is "creationDate" from Permission a necessary field for the user? Not really.
2) Is "id" from Permission a necessary field for the user? In some cases yes, in others, not.
A possible CustomerDTO could look like this:
public class CustomerDTO
{
private String firstName;
private String lastName;
private List<String> permissions;
}
and you can notice that I'm using a List<String> instead of List<Permission> for customer's permissions which are in fact the permissions' names.
public CustomerDTO convertModelToDto(Customer customer)
{
//hard way
CustomerDTO customerDTO = new CustomerDTO();
customerDTO.setFirstName(customer.getFirstName());
customerDTO.setLastName(customer.getLastName());
customerDTO.setPermissions(
customer.getPermissions()
.stream()
.map(permission -> permission.getName())
.collect(Collectors.toList());
);
// easy-way => using a ModelMapper
customerDTO = modelMapper.map(customer,CustomerDTO.class);
return customerDTO;
}
Use ModelMapper to map one model into another.
First define a function that can map source data into the target model. Use this as a library to use whenever want.
public static <T> void merge(T source, T target) {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
modelMapper.map(source, target);
}
Use merge for mapping data
Customer customer = customerRepository.findById(id).get();
merge(newCustomer, customer);
customerRepository.save(customer);
Add dependency in pom.xml for model mapper
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.4</version>
</dependency>
How can one configure their JPA Entities to not fetch related entities unless a certain execution parameter is provided.
According to Spring's documentation, 4.3.9. Configuring Fetch- and LoadGraphs, you need to use the #EntityGraph annotation to specify fetch policy for queries, however this doesn't let me decide at runtime whether I want to load those entities.
I'm okay with getting the child entities in a separate query, but in order to do that I would need to configure my repository or entities to not retrieve any children. Unfortunately, I cannot seem to find any strategies on how to do this. FetchPolicy is ignored, and EntityGraph is only helpful when specifying which entities I want to eagerly retrieve.
For example, assume Account is the parent and Contact is the child, and an Account can have many Contacts.
I want to be able to do this:
if(fetchPolicy.contains("contacts")){
account.setContacts(contactRepository.findByAccountId(account.getAccountId());
}
The problem is spring-data eagerly fetches the contacts anyways.
The Account Entity class looks like this:
#Entity
#Table(name = "accounts")
public class Account
{
protected String accountId;
protected Collection<Contact> contacts;
#OneToMany
//#OneToMany(fetch=FetchType.LAZY) --> doesn't work, Spring Repositories ignore this
#JoinColumn(name="account_id", referencedColumnName="account_id")
public Collection<Contact> getContacts()
{
return contacts;
}
//getters & setters
}
The AccountRepository class looks like this:
public interface AccountRepository extends JpaRepository<Account, String>
{
//#EntityGraph ... <-- has type= LOAD or FETCH, but neither can help me prevent retrieval
Account findOne(String id);
}
The lazy fetch should be working properly if no methods of object resulted from the getContacts() is called.
If you prefer more manual work, and really want to have control over this (maybe more contexts depending on the use case). I would suggest you to remove contacts from the account entity, and maps the account in the contacts instead. One way to tell hibernate to ignore that field is to map it using the #Transient annotation.
#Entity
#Table(name = "accounts")
public class Account
{
protected String accountId;
protected Collection<Contact> contacts;
#Transient
public Collection<Contact> getContacts()
{
return contacts;
}
//getters & setters
}
Then in your service class, you could do something like:
public Account getAccountById(int accountId, Set<String> fetchPolicy) {
Account account = accountRepository.findOne(accountId);
if(fetchPolicy.contains("contacts")){
account.setContacts(contactRepository.findByAccountId(account.getAccountId());
}
return account;
}
Hope this is what you are looking for. Btw, the code is untested, so you should probably check again.
You can use #Transactional for that.
For that you need to fetch you account entity Lazily.
#Transactional Annotations should be placed around all operations that are inseparable.
Write method in your service layer which is accepting one flag to fetch contacts eagerly.
#Transactional
public Account getAccount(String id, boolean fetchEagerly){
Account account = accountRepository.findOne(id);
//If you want to fetch contact then send fetchEagerly as true
if(fetchEagerly){
//Here fetching contacts eagerly
Object object = account.getContacts().size();
}
}
#Transactional is a Service that can make multiple call in single transaction
without closing connection with end point.
Hope you find this useful. :)
For more details refer this link
Please find an example which runs with JPA 2.1.
Set the attribute(s) you only want to load (with attributeNodes list) :
Your entity with Entity graph annotations :
#Entity
#NamedEntityGraph(name = "accountGraph", attributeNodes = {
#NamedAttributeNode("accountId")})
#Table(name = "accounts")
public class Account {
protected String accountId;
protected Collection<Contact> contacts;
#OneToMany(fetch=FetchType.LAZY)
#JoinColumn(name="account_id", referencedColumnName="account_id")
public Collection<Contact> getContacts()
{
return contacts;
}
}
Your custom interface :
public interface AccountRepository extends JpaRepository<Account, String> {
#EntityGraph("accountGraph")
Account findOne(String id);
}
Only the "accountId" property will be loaded eagerly. All others properties will be loaded lazily on access.
Spring data does not ignore fetch=FetchType.Lazy.
My problem was that I was using dozer-mapping to covert my entities to graphs. Evidently dozer calls the getters and setters to map two objects, so I needed to add a custom field mapper configuration to ignore PersistentCollections...
GlobalCustomFieldMapper.java:
public class GlobalCustomFieldMapper implements CustomFieldMapper
{
public boolean mapField(Object source, Object destination, Object sourceFieldValue, ClassMap classMap, FieldMap fieldMapping)
{
if (!(sourceFieldValue instanceof PersistentCollection)) {
// Allow dozer to map as normal
return;
}
if (((PersistentCollectiosourceFieldValue).wasInitialized()) {
// Allow dozer to map as normal
return false;
}
// Set destination to null, and tell dozer that the field is mapped
destination = null;
return true;
}
}
If you are trying to send the resultset of your entities to a client, I recommend you use data transfer objects(DTO) instead of the entities. You can directly create a DTO within the HQL/JPQL.
For example
"select new com.test.MyTableDto(my.id, my.name) from MyTable my"
and if you want to pass the child
"select new com.test.MyTableDto(my.id, my.name, my.child) from MyTable my"
That way you have a full control of what is being created and passed to client.
I am writing my first Spring MVC webapp and have a question about DAOs and web service requests.
Essentially my app allows the user to construct an order, which gets persisted to a database via a DAO. Later on a scheduled worker will retrieve the new orders from the database, submit them to a third-party SOAP service and update each order with some details (e.g. order number).
My controller calls the OrderService (a condensed version):
#Service
public class OrderService {
#Autowired
private OrderDao orderDao;
public List<Order> getOrderList() {
List<Order> orders = orderDao.getAllOrders();
return orders;
}
public void addNewOrder(Order order) {
orderDao.addOrder(order);
}
}
The OrderService calls the OrderDao:
#Repository
public class OrderDao extends JdbcDaoSupport {
#Autowired
public OrderDao(DataSource dataSource) {
setDataSource(dataSource);
}
public List<Order> getAllOrders() {
String sqlQuery = "SELECT id, name, status, orderNumber FROM orders";
List<Order> orders = getJdbcTemplate().query(sqlQuery, new OrderRowMapper());
return orders;
}
public int addOrder(Order order) {
String sqlQuery = "INSERT INTO orders (name, status) VALUES (?, ?)";
getJdbcTemplate().update(sqlQuery, new Object[] { order.getName(), order.getStatus() });
return getJdbcTemplate().queryForObject("SELECT LAST_INSERT_ID()", Integer.class );
}
}
The Order model looks like:
public class Order {
private int orderId;
private String name;
private String status;
private String orderNumber;
// getters and setters etc.
}
At present my OrderDao only communicates with the database to perform CRUD actions on the Order model. I am not sure whether I should create a placeOrder() method within the OrderDao as this would mean I have a single DAO that accesses both database and SOAP service, which feels wrong.
It also feels wrong to put placeOrder() in the OrderService because the service will contain a mixture of internal DAO calls and external third-party SOAP calls.
I've been reading up on interfaces but I don't think they help me here as my database DAO would contain create(), update(), delete() which wouldn't apply to a SOAP DAO.
Should I just create two DAOs: OrderDaoDatabase and OrderDaoSoap?
The point of using layered architecture is to encourage decoupling and separation of concerns. You already have the service layer to take care of business logic and data access layer (DAOs) to communicate with the database, that seems to be right. OrderService should talk to the database and OrderDAO should talk to the database.
Your scheduled worker seems to be a different class. OrderDAO can expose the order(s) data through different methods (which are required by your application). If placeOrder() is a call to external web service, it's okay to call that from an appropriate method within OrderService or a different class if required. Now, since that call isn't done at the time addOrder() is called, it probably belongs to a different method which is invoked by the scheduler. On the other hand, I don't think placeOrder() should go into OrderDAO, it should be left for what it says - data access object.