JPA: Fetch data from DB instead of Persistance Context - java

I have a simple User Account application in which the user is able to change his details.
Updating the Database
The Managed Bean's method which takes the form parameters and calls the Service method:
public String changeDetails(){
Date date = DateUtil.getDate(birthDate);
Integer id = getAuthUser().getId();
UserDetail newDetails = new UserDetail(id, occupation, date, originCity, residenceCity, description);
EntityTransaction transaction = getTransaction();
userService.updateDetail(newDetails);
transaction.commit();
return null;
}
The Service Method:
public boolean updateDetail(UserDetail newDetails) {
boolean ok = true;
if (newDetails != null) {
UserDetail user = readDetail(newDetails.getId());
user.setOccupation(newDetails.getOccupation());
user.setOriginCity(newDetails.getOriginCity());
user.setResidenceCity(newDetails.getResidenceCity());
user.setBirth(newDetails.getBirth());
user.setDescription(newDetails.getDescription());
}
return ok;
}
Fetching data from DB
#PostConstruct
public void init(){
userService = new UserService();
sessionController.setAuthUser(userService.read(getAuthUser().getId()));
originCity = getAuthUser().getUserDetail().getOriginCity();
residenceCity = getAuthUser().getUserDetail().getResidenceCity();
occupation = getAuthUser().getUserDetail().getOccupation();
birthDate = DateUtil.getStringDate(getAuthUser().getUserDetail().getBirth());
description = getAuthUser().getUserDetail().getDescription();
}
The problem is that the behavior of this code is different. Sometimes I obtain the desired result: once I submit the new details and call the #PostConstruct init () the new details are printed. Some other times the old details are printed even though the DB entry is updated.
Conclusion: Sometimes the JPA brings me different result from what is in the DB. I guess that this results consist of data from the Persistance Context, data which isn't updated. Is there a way in which I can be sure that the JPA always brings the data directly from the DB? Or is there something I'm missing?

If you are using JPA 2 then #Cacheable(false) on your entity definition should make it read from the DB every time.

You mean is there a way to turn the cache off or empty it before an operation ?
emf.getCache().evictAll();

Related

entity retrieved from cache is not updated by the #Transactional in spring boot

I am retrieving the User session from redis cache and making changes to the child entity
The changes made is not updated to the database with the help of the #Transactional Annotation
#Transactional
public ResponseEntity<Object> updateRating(#NonNull final String sessionId, #NonNull final UserRatingUpdateRequestDTO userRatingUpdateRequestDTO) {
final UserSession fetchedSession = userSessionService.findUserSessionBySessionId(sessionId);
final User user = fetchedSession.getUser();
final LocalDate currentDate = DateTimeUtils.dateTimeInIST().toLocalDate();
logger.info("Updating Rating for user : {}", user.getId());
if (userRatingUpdateRequestDTO.isHasRated()) {
user.getUserRating().setHasGivenRating(true);
} else {
int weeksToAdd = 5;
user.getUserRating().setDate(currentDate.plusWeeks(weeksToAdd));
}
cacheInvalidatorService.evictUserSession(sessionId);
cacheInvalidatorService.deleteUserDetails(user.getUsername());
return ResponseEntity.ok().body("rating updated successfully");
}
}
I tried to create a new transaction but the changes not reflecting into the database
I tried to use the Commit but that only be used inside the testing method
I want to update the database with the help of transaction annotation and with out saving the entity
or is it not possible

How to update postgres table with Spring Boot JPARepository?

I have a Spring boot application thats committing object to Postgres DB using JPARepository. The code for my repository is as below:
public interface TestObjectDao extends JPARepository<TestObject, Long> {
List<TestObject> findByTestRefIdAndTestType(String testRefId,
Short testType);
TestObject save(TestObject testObject);
}
When I want to create, In my service implementation (implementing above interface) I used "save" method. But, when I try to update, it neither creates entry nor update it.
How can I update records in Postgres database? Below is my code snippet using for update:
#Component
public class TestObjectServiceImpl implements TestObjectService {
#Inject
private TestObjectDao TestObjectDao;
#Override
public TestObjectResponse createTestObject(String testRefId, String testType, TestObject testObject) throws Exception{
--
--
--
try {
//update object
testObject = TestObjectDao.save(testObject);
}
}
catch (Exception ex) {
throw new Exception("Object could not be modified");
}
TestObjectResponse testObjectResponse = new TestObjectResponse();
testObjectResponse.setVal(testObject);
return testObjectResponse;
}
}
I have gone through all related posts but didn't get satisfactory resolution.
Spring detects wether it needs to save or create an entity by checking it's ID.
In your case, you need to select it first, so Spring will populate the entity properly:
try {
testObject = TestObjectDao.findOne(testRefId);
//update object
testObject = TestObjectDao.save(testObject);
}
Please refer section 2.2.1:
http://docs.spring.io/spring-data/jpa/docs/1.4.1.RELEASE/reference/html/jpa.repositories.html
Note that if only some columns are to be updated, it's much more efficient to use:
#Modifying
#Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);

how to define a keyspace dynamically in accessor

I am attempting to create an accessor to run slightly more complex queries in cassandra with java. I have no problem with the syntax, and I can get it to work, but my question is this: is there a way to dynamically declare a keyspace in an accessor?
For example, if you create a table map for the MappingManager you would declare the #Table and give it the keyspace and table name like so:
#Table(keypace="mykeyspace", name="orders")
public class Orders {
#PartitionKey
public UUID id;
//blah blah blah, rest of code
}
Now creating an accessor for that specific table is easy enough:
#Accessor
public interface OrdersAccessor {
#Query("SELECT * FROM orders WHERE status = :status")
Result pending(#Param("status") Integer status);
}
Simple. The problem is it demands a keyspace, and I am a huge fan of never hard-coding anything. I realize that I am "hard-coding" the keyspace in the Table definition in the MappingManager class definition, but if need be I only change it there and it updates everything that has to do with that. If I hard-code the keyspace in every single #Query definition inside the Accessor I will have to change, potentially, a bunch of different items if the keyspace gets updated, instead of only changing it one place in the #Table definition.
I have been searching Google for hours and I can't find a single instance of someone dynamically declaring a keyspace with an accessor, only thousands of examples of accessors where they are hard-coding the keyspace into the #Query like so:
#Accessor
public interface OrdersAccessor {
#Query("SELECT * FROM keyspace.orders WHERE status = :status")
Result pending(#Param("status") Integer status);
}
I realize the query I wrote isn't really cause for an accessor, I was just simplifying it for the sake of the example. So I am coming to the community asking for help, I can't find any examples of this anywhere. I can't imagine that I am the first person to ever want to do this, I just can't find any examples of anyone else tackling this problem. Thank you in advance for any help you can give, I can really use it.
#Sudhir Here is the solution I came up with. I am sure there are better ways to handle the connections, but I am still pretty new to cassandra and Java, and this is working well for my needs. I hope this helps...
public class DbInterface {
private Cluster cluster;
private Session session;
private Map<String, Session> dbMap;
private Map<String, Map<String, Mapper<Class>>> mappers = new ConcurrentHashMap<>();
public DbInterface(String host) {
Map<String, Session> connections = createConnection(host);
Session crSession = connections.get("crSession");
Session hppSession = connections.get("hppSession");
cluster = Cluster.builder().addContactPoint(host).build();
Session crSession = cluster.connect("mykeyspace");
Session hppSession = cluster.connect("hpp");
MappingManager crManager = new MappingManager(crSession);
MappingManager hppManager = new MappingManager(hppSession);
mappers.put("mykeyspace", new ConcurrentHashMap<>());
mappers.put("mykeyspace2", new ConcurrentHashMap<>());
Map cr = mappers.get("mykeyspace");
Map hpp = mappers.get("mykeyspace2");
cr.put("status", crManager.mapper(OrderStatus.class));
hpp.put("status", hppManager.mapper(OrderStatus.class));
cr.put("status_accessor", crManager.createAccessor(OrderStatusAccessor.class));
hpp.put("status_accessor", hppManager.createAccessor(OrderStatusAccessor.class));
cr.put("users", crManager.mapper(Users.class));
hpp.put("users", hppManager.mapper(Users.class));
cr.put("orders", crManager.mapper(Orders.class));
hpp.put("orders", hppManager.mapper(Orders.class));
cr.put("order_detail", crManager.mapper(OrderDetail.class));
hpp.put("order_detail", hppManager.mapper(OrderDetail.class));
cr.put("chal_orders", crManager.mapper(ChalOrder.class));
hpp.put("chal_orders", hppManager.mapper(ChalOrder.class));
cr.put("chal_order_detail", crManager.mapper(ChalOrderDetail.class));
hpp.put("chal_order_detail", hppManager.mapper(ChalOrderDetail.class));
cr.put("detail_accessor", crManager.createAccessor(OrderDetailAccessor.class));
hpp.put("detail_accessor", hppManager.createAccessor(OrderDetailAccessor.class));
cr.put("tracking_labels", crManager.mapper(TrackingLabels.class));
hpp.put("tracking_labels", hppManager.mapper(TrackingLabels.class));
}
public Session getConnection(String type) {
if(dbMap.containsKey(type)) {
return dbMap.get(type);
}
if(dbMap.containsKey(type.toLowerCase() +"Session")) {
return dbMap.get(type.toLowerCase() +"Session");
}
return dbMap.get("crSession");
}
public Map<String, Session> createConnection(String host) {
dbMap = new HashMap<>();
cluster = Cluster.builder().addContactPoint(host).build();
Session crSession = cluster.connect("mykeyspace");
Session hppSession = cluster.connect("hpp");
dbMap.put("crSession", crSession);
dbMap.put("hppSession", hppSession);
return dbMap;
}
public Map getDBMap(String client) {
if(mappers.containsKey(client)) {
return mappers.get(client);
}
throw new RuntimeException("Unknown Client: " + client);
}
}
One of the things I was thinking of doing is moving the session creation and Map creation to separate functions, then only connect and build the map for the session that is needed. Like instead of defaulting to connecting to both sessions when the DbInterface() is called, only connect to the session that is requested via the "host" param.
Anywho, I hope this helps you out. If you need it, here is an example of my other library that uses this...
public class MyRestController {
private final DbInterface db = new DbInterface(IPADDRESS);
#CrossOrigin
#RequestMapping("/status")
public String getStatus() {
Map managerMap = db.getDBMap("mykeyspace");
OrderStatusAccessor statuses = (OrderStatusAccessor) managerMap.get("status_accessor");
Result<OrderStatus> allStatuses = statuses.getAll();
//rest of the code here
}
}

DB management using Entity Objects

I have a bean in my Fusion Web Application where I'm supposed to insert new data into a table of my database through java code (after appropriate validation).
The question is how should I do the insertion?
Should I use Entity Objects?
How?
P.S.: This is not the way it should work http://jneelmani.blogspot.com/2009/11/adf-insert-using-storeprocedure.html
I created Entity Object and View Object by the database table "Employees" and then created application module where included this view object (also were generated java classes for entity object, view object and appModule. EmployeeInfo is just POJO). Inside the application module I created methods:
public EmployeeViewRowImpl saveEmployee(EmployeeInfo EmployeeInfo) {
// Получаем ViewObject
EmployeeViewImpl employeeView = getEmployeeView1();
// Готовим новую строку.
EmployeeViewRowImpl employee = createEmployeeViewRowImpl(employeeView, employeeInfo);
// Производим операцию вставки.
employeeView.insertRow(employee);
// Коммитим
try {
getDBTransaction().commit();
return employee;
} catch (JboException e) {
getDBTransaction().rollback();
return null;
}
}
private EmployeeViewRowImpl createEmployeeViewRowImpl(EmployeeViewImpl employeeView, EmployeeInfo employeeInfo) {
EmployeeViewRowImpl employee = (EmployeeViewRowImpl)EmployeeView.createRow();
employee.setName(employeeInfo.getName());
return employee;
}
And to use this one should just call:
public static AppModuleImpl getApp() {
return (AppModuleImpl)Configuration.
createRootApplicationModule(
"com.test.service.AppModule", // where your module is stored
"AppModuleShared"); // chosen configuration
}
and then
...
RegistrationAppModuleImpl app = getApp();
app.saveUser(userInfo)
...
May be i'm not to clear on the dynamics of what you are trying to do, but with Oracle ADF, CRUD operations (such as Insert), are easily handled by exposing them from Data Controls. To be more specific, once you have an EO, you should create a View Object and an Application Module. After that, inside the AppMod -> Data Model , add the created VO. This way it will be exposed in the Data Controls panel, and you can expand the 'Operations' folder, and drag'n'drop the CreateInsert operation possibly within a form, or an updatable table.
Please refer to this link: CreateInsert Operation - ADF.
If for some other reason you want to handle this process in a programmatic approach, i might think about two possible ways:
1. Get into your managed bean code an instance of the above mentioned AppMod, and from that, a VO instance.
AppModule mod = AppModule)Configuration.createRootApplicationModule("packageName.AppModule", "AppModuleLocal");
ViewObject vo = mod.getViewObject1();After that, create a new row and commit the newly added values.
2. If you have already exposed a UI component (such a table), you can grab the Binding Context of the current page and from the table's iterator, create a new row.
DCBindingContainer DCB = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
DCIteratorBinding iterator = bc.findIteratorBinding("ViewObject1Iterator");
Row r = iterator.getCurrentRow();
r.setAttribute("attibName", attribValue);
You can do the insertion using entity object as below:
/* Create a new Customer and Return the new id */
public long createCustomer(String name, String city, Integer countryId) {
EntityDefImpl customerDef = CustomerImpl.getDefinitionObject();
CustomerImpl newCustomer =
(CustomerImpl)customerDef.createInstance2(getDBTransaction(),null);
newCustomer.setName(name);
newCustomer.setName(name);
newCustomer.setCountryId(countryId);
try {
getDBTransaction().commit();
}
catch (JboException ex) {
getDBTransaction().rollback();
throw ex;
}
DBSequence newIdAssigned = newCustomer.getId();
}

role field not stored in database after identitymanager role creation

I'm using seam 2.1.2 security and I create a role using identitymanager by jsf richfaces GUI. in creation process I would add a "description" to role created in database , the creation of role is ok but the description field is not added, I must update the role (in other operation by GUI) to see the description field stored in database. the question is what have I to do to store the "description" filed in creation operation?
bellow is my code:
public boolean createRole(Role role) {
IdentityManager identityManager = IdentityManager.instance();
logger.info("creating role:" + role.getRoleName());
if (identityManager.roleExists(role.getRoleName())) {
return false;
}
if (identityManager.createRole(role.getRoleName())) {
completeRolePersistence(role);
return true;
}
return false;
}
and the completeRolePersistence method:
public void completeRolePersistence(Role role) {
logger.info("setting additional info to role...");
Query query = em.createNamedQuery("UPDT_ADDITIONALS");
query.setParameter("name", role.getRoleName())
.setParameter("description", role.getDescription())
.setParameter("level", role.getRoleLevel());
int updated = query.executeUpdate();
logger.info("roles updated with desc : " + updated);
}
it seem that the query is not executed , i print in log
roles updated with desc : 0
The reason your code does not work is because your update query is executing BEFORE the role is actually inserted into the database, thus it updates nothing.
My advice is to not use the role/user creation methods in IdentityManager. You're better off creating Home components to create/edit your roles and users than having IdentityManager do it for you.
If you however want to pursue this, you need to overwrite JpaIdentityStore, customize the createRole method and have it populate the entity as needed.

Categories

Resources