I am using GraphiQL in my project. I have an issue when deleting a record, called from another service. I am using Postgres DB.
EmployeeMutation.java:
#DgsData(parentType = "MutationResolver", field = "detachParty")
public Boolean deleteEmployee(#InputArgument("id") Long id) {
return employeeService.deleteEmployee(id);
}
EmployeeService.java:
public boolean deleteEmployee(Long id) {
final var employeeEntity = repository.findById(id);
if (employeeEntity.isPresent()) {
repository.delete(employeeEntity.get());
return true;
} else {
return false;
}
Above works fine if I call the deleteEmployee mutation API from GraphiQL editor. But if I call the above service separately from another service, deletion is not happening.
employeeService.deleteEmployee(employeeEntity.getId());
I am calling above method from another service (DepartymentService). In another service employeeService is autowired and also Id is also passed correctly but deletion is not happening.
I also tried directly calling using employee repository in Department Service but still deletion is not working. What can I try next?
Related
I'm trying to migrate my project to Quarkus Reactive with Hibernate Reactive Panache and I'm not sure how to deal with caching.
My original method looked like this
#Transactional
#CacheResult(cacheName = "subject-cache")
public Subject getSubject(#CacheKey String subjectId) throws Exception {
return subjectRepository.findByIdentifier(subjectId);
}
The Subject is loaded from the cache, if available, by the cache key "subjectId".
Migrating to Mutiny would look like this
#CacheResult(cacheName = "subject-cache")
public Uni<Subject> getSubject(#CacheKey String subjectId) {
return subjectRepository.findByIdentifier(subjectId);
}
However, it can't be right to store the Uni object in the cache.
There is also the option to inject the cache as a bean, however, the fallback function does not support to return an Uni:
#Inject
#CacheName("subject-cache")
Cache cache;
//does not work, cache.get function requires return type Subject, not Uni<Subject>
public Uni<Subject> getSubject(String subjectId) {
return cache.get(subjectId, s -> subjectRepository.findByIdentifier(subjectId));
}
//This works, needs blocking call to repo, to return response wrapped in new Uni
public Uni<Subject> getSubject(String subjectId) {
return cache.get(subjectId, s -> subjectRepository.findByIdentifier(subjectId).await().indefinitely());
}
Can the #CacheResult annotations be used with Uni / Multi and everything is handled under the hood correctly?
Your example with a #CacheResult on a method that returns Uni should actually work. The implementation will automatically "strip" the Uni type and only store the Subject in the cache.
The problem with caching Unis is that depending on how this Uni is created, multiple subscriptions can trigger some code multiple times. To avoid this you have to memoize the Uni like this:
#CacheResult(cacheName = "subject-cache")
public Uni<Subject> getSubject(#CacheKey String subjectId) {
return subjectRepository.findByIdentifier(subjectId)
.memoize().indefinitely();
}
This will ensure that every subscription to the cached Uni will always return the same value (item or failure) without re-executing anything of the original Uni flow.
My Audit logs are getting out of hand so I decided I want to only audit all requests which basically are not a Get request. Is there a very simply way to do this from configuration?
The documentation here:
https://aspnetboilerplate.com/Pages/Documents/Audit-Logging
Says:
Note: In addition to the standard audit configuration, MVC and ASP.NET
Core modules define configurations to enable/disable audit logging for
actions.
But I could not find more information about what exactly this means.
As a last resort, I know it would work if I went to every class and added [DisableAuditing] and then [Audited] on the non-Get endpoints, but that seems a bit messy.
Best soltuion: I just want to have a simply way to select only non-GET requests and audit them.
Second best solution:
I just want to have only [Audited] methods audited. I don't want to have to go and write [DisabledAuditing] on every class.
You can create an AuditStore to do that, and then replace the original AuditStore in service YourAplicationNameCoreModule
Here is the example
public class YourAuditStore : AuditingStore
{
public ILogger<AuditingStore> Logger { get; set; }
private readonly IRepository<AuditLog, long> _auditLogRepository;
private readonly ISettingManager _settingManager;
public YourAuditStore(IRepository<AuditLog, long> auditLogRepository, ISettingManager settingManager) : base(auditLogRepository)
{
_auditLogRepository = auditLogRepository;
_settingManager = settingManager;
}
public override async Task SaveAsync(AuditInfo auditInfo)
{
AuditLog auditLog = new AuditLog();
bool logErrorsOnly = await _settingManager.GetSettingValueAsync<bool>(AppSettings.Logging.LogOnErrorsOnly);
var exceptionMessage = auditInfo.Exception != null ? auditInfo.Exception.ToString() : null;
if ((logErrorsOnly && exceptionMessage != null) || !logErrorsOnly)
{
auditLog = await _auditLogRepository.InsertAsync(AuditLog.CreateFromAuditInfo(auditInfo));
}
}
}
As you can see, you can filter whatever you want in SaveAsync method as it recieve the AuditInfo, you can check if method is different to Get then save
Add the next code to YourApplicationNameCoreModule on PreInitialize method
public override void PreInitialize()
{
Configuration.ReplaceService<IAuditingStore, YourAuditStore>();
}
I am working by spring data to access database and do not use any cache. I have a problem that after deleting a record from database, I am sending an event to other micro system to re-query to update list of objects. So basically my code is :
private void deleteObject(MyObject object) {
myRepository.deleteById(object.getId());
myRepository.flush();
...
sendEventToSystemX();
}
Basically other micro service captures the event which is sent by sendEventToSystemX method and make a query to myRepository.
#Transactional(isolation = Isolation.READ_UNCOMMITTED, readOnly = true)
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
TypedQuery<T> query = getQuery(spec, getDomainClass(), pageable.getSort());
if(pagable.isUnpaged()) {
return new PageImpl<>(query.getResultList())
}
return readPage(query, getDomainClass(), pageable, spec);
}
So note that I am flushing repo after deletion. And select query is done by different service so it is not in the same transaction. So why I still get deleted object for the first time I query after deletion. If I re-run findAll method then I get up-to data result. And this also does not happen always. So what can be reason behind it ?
I want to use cache in my application using ehcache with spring boot.
So i want to cache a list of users and when admin want to find user by email for example not use JpaRepository but i want to find in list of users cachable.
To cache list of users i write below code
#Override
#Cacheable(cacheNames = "users")
public List<User> getList() {
return userRepository.findAll();
}
To find a user by email i use for instant code like below :
List<User> users = getList();
User userByEmail(String email){
for(User user: users){
if(user.getEmail().equals(email)){
return user;
}
}
return null;
}
I know this is not a good why, but i don't find a good solution.
Anyone help me to use cache correctly and find user using Cacheable list of users.
You should have a method which takes email as an input and returns user with that email from database.
Add #cacheable on that method so that it will only execute an expensive query to the database first time and add the result to the cache .For any subsequent call to the method it will return the data from cache without actually executing the body of the method.
#Cacheable("users")
public User getUserByEmail(String email) {
return userRepository.findUserByEmail(email);
}
You can create a new method as below
#Cacheable(value = "user", key = "#email")
public User findUserByEmail(String email) {
//Logic to retrieve the data
}
The first time you call this method it will fetch the data from the source and popular the Cache. Next time you will get it from the Cache.
I am working with Spring 4 and Hazelcast 3.2. I am trying to add a new record to existing cache with below code. somehow cache is not getting updated and at the same time I don't see any errors also. below is the code snippet for reference.
Note:- Cacheable is working fine, only cacheput is not working. Please throw light on this
#SuppressWarnings("unchecked")`enter code here`
#Transactional(readOnly = true, propagation = Propagation.REQUIRED)
#Cacheable(value="user-role-data")
public List<User> getUsersList() {
// Business Logic
List<User> users= criteriaQuery.list();
}
#SuppressWarnings("unchecked")
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
#CachePut(value = "user-role-data")
public User addUser(User user) {
return user;
}
I had the same issue and managed to solved it. The issue seemed to be tied to the transaction management.
Bascially updating the cache in the same method where you are creating or updating the new record does not work because the transaction was not committed. Here's how I solved it.
Service layer calls repo to insert user
Then go back to service layer
After the insert /update db call
In the service layer I called a refresh cache method
That returned the user data and this method has the cacheput annotation
After that it worked.
An alternative approach is you could use #CacheEvict(allEntries = true) on the method used to Save or Update or Delete the records. It will flush the existing cache.
Example:
#CacheEvict(allEntries = true)
public void saveOrUpdate(Person person)
{
personRepository.save(person);
}
A new cache will be formed with updated result the next time you call a #Cacheable method
Example:
#Cacheable // caches the result of getAllPersons() method
public List<Person> getAllPersons()
{
return personRepository.findAll();
}