Insert in DB for multiple records not working in webflux R2DBC - spring-boot

I am trying to insert some records in DB in one go, also tried for loop but it never happens, If I save a single record, it works
#RequiredArgsConstructor
#Service
public class UserServiceImpl {
private final UserRepository userRepo;
private final FamilyRepository familyRepo;
public Mono<ServerResponse> insertUserData(ServerRequest serverRequest) {
return serverRequest.bodyToMono(UserAndFamilyRequest.class)
// .map(userAndFamilyRequest -> {
// List<FamilyMember> list = userAndFamilyRequest.getFamilyMemberList();
// list.stream().forEach((familyMember) ->
// {
// System.out.println(familyMember.getName());
// FamilyMemberEntity familyMemberEntity = new FamilyMemberEntity();
// familyMemberEntity.setAge(familyMember.getAge());
// familyMemberEntity.setName(familyMember.getName());
// familyRepo.save(familyMemberEntity);//doesn't work either
// try{
// Thread.sleep(2000);
// }catch(Exception ex){
//
// }
//
// });
// return userAndFamilyRequest;
// })
.map(userAndFamilyRequest -> {
List<FamilyMember> list = userAndFamilyRequest.getFamilyMemberList();
var entityList = list.stream().map(familyMember -> {
FamilyMemberEntity familyMemberEntity = new FamilyMemberEntity();
familyMemberEntity.setName(familyMember.getName());
familyMemberEntity.setAge(familyMember.getAge());
return familyMemberEntity;
}).collect(Collectors.toList());
familyRepo.saveAll(entityList);//doesn't work
return userAndFamilyRequest;
})
.flatMap(userAndFamilyRequest -> {
UserEntity userEntity = new UserEntity();
User user = userAndFamilyRequest.getUser();
userEntity.setSeats(userAndFamilyRequest.getFamilyMemberList().size());
userEntity.setAge(user.getAge());
userEntity.setName(user.getName());
return userRepo.save(userEntity);
})
// .flatMap(userAndFamilyRequest -> {
// FamilyMember familyMember = userAndFamilyRequest.getFamilyMemberList().get(0);
// FamilyMemberEntity familyMemberEntity = new FamilyMemberEntity();
// familyMemberEntity.setAge(familyMember.getAge());
// familyMemberEntity.setName(familyMember.getName());
// return familyRepo.save(familyMemberEntity);//single save works
// })
.flatMap(userEntity -> ServerResponse.created(URI.create("users"+userEntity.getId()))
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(userEntity));
}
}
no error in the console

add try {} catch in function save data, so you can know what error you face it

Well I found the answer by myself, the familyRepo.save inside map will not work by itself because it returns a Flux which will execute only when subscribed, replacing it with flatMap(which automatically subscribes) resolved the issue.

Related

Springboot webflux reactor delete items from mongoDB

I use springboot + mongodb, and I am a beginer for webflux. I write code for CRUD. When I access delete ids in Controller, code not working because count alway return 0. Any one help me?
#ApiOperation(value = "Delete multi cities")
#DeleteMapping
public Mono<ResponseEntity<AtomicInteger>> deleteByIds(#RequestBody #NotNull Set<String> ids) {
AtomicInteger count = new AtomicInteger(0);
Flux.fromIterable(ids)
.flatMap((id) -> {
return cityService.findById(id)
.flatMap((c) -> {
count.getAndAdd(1);
return cityService.deleteById(c.getId());
});
});
log.debug("count = {}", count);
return Mono.just(ResponseEntity.ok(count));
}
The Flux is not be subscribed
you should try like this
return Flux.fromIterable(ids)
.flatMap((id) -> {
return cityService.findById(id)
.flatMap((c) -> {
count.getAndAdd(1);
return cityService.deleteById(c.getId());
});
})
.then(Mono.defer(() -> {
log.debug("count = {}", count);
return Mono.just(ResponseEntity.ok(count));
}));

Skip chain of CompletableFuture based on a specific condition

There are several CompletionFutures methods that I'd like to chain. The problem is that I want to skip other chain and go to last method of the pipeline if some condition is met. Mentioned as comment in the below code. For example:
public CompletableFuture<Void> process() {
CompletableFuture<Set<String>> service1 = new CompletableFuture();
return service1
.thenCompose(data -> {
if (!data.isEmpty()) {
SomeObject obj = prepareSomeObject();
obj.addAll(data.stream().collect(Collectors.toSet()));
//Here want to check some condition and if it meets, then go to last method of the pipeline
//Otherwise continue with the current flow
CompletableFuture<String> someFuture = new CompletableFuture<>();
CompletableFuture<String> someOtherFuture= new CompletableFuture<>();
return CompletableFuture.allOf(someFuture, someOtherFuture)
.thenApply(aVoid -> {
String user = someFuture.join();
String unit = someOtherFuture.join();
obj.setUnit(unit);
obj.setUser(user)
return obj;
})
.thenCompose(this::someMethod)
.thenCompose(this::someOtherMethod); // last method in the pipeline
}
return completedFuture(null);
});
}
I have tried something like this, Please critique on the right way to do it.
public CompletableFuture<Void> process() {
CompletableFuture<Set<String>> service1 = new CompletableFuture();
return service1
.thenCompose(data -> {
if (!data.isEmpty()) {
SomeObject obj = prepareSomeObject();
obj.addAll(data.stream().collect(Collectors.toSet()));
if(condition not match) { //condition match
CompletableFuture<String> someFuture = new CompletableFuture<>();
CompletableFuture<String> someOtherFuture= new CompletableFuture<>();
return CompletableFuture.allOf(someFuture, someOtherFuture)
.thenApply(aVoid -> {
String user = someFuture.join();
String unit = someOtherFuture.join();
obj.setUnit(unit);
obj.setUser(user)
})
.thenCompose(this::someMethod)
.thenCompose(this::someOtherMethod); // last method in the pipeline
} else return someOtherMethod(obj);
}
return completedFuture(null);
});
}

JavaFX: How to trigger TreeItem event

I have class myClass extends TreeItem<file> to be used as datamodel in a TreeTableView mostly following the example here: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TreeItem.html .
public class myTreeItem extends TreeItem<File>
private boolean isLeaf;
private boolean isFirstTimeChildren = true;
private boolean isFirstTimeLeaf = true;
#Override public ObservableList<TreeItem<File>> getChildren() {
// ... full code see link to Oracle documentation
return super.getChildren();
}
private ObservableList<TreeItem<File>> buildChildren(TreeItem<File> TreeItem) {
// ... full code see link to Oracle documentation
};
}
I have added a function to add children to this item. I have problems with the correct update of the TreeTableView. More details see in the code and comments below:
public void addChild(String name) {
itemManger.addChild(this.getValue(), name); // Generate Child
isFirstTimeChildren = true; // Ensure that buildChildren() is called, when getchildren() is called.
// getChildren(); // If I would activate this line,
// all listeners would be notified
// and the TreeTableView is updated.
// This is most likely due to the call super.getChildren();
// However I want to throw the event on my own in order
// to avoid the extra call of this.getChildren(). Here is my
// (not sufficent) try:
EventType<TreeItem.TreeModificationEvent<MLDCostumizableItem>> eventType = TreeItem.treeNotificationEvent();
TreeModificationEvent<MLDCostumizableItem> event = new TreeModificationEvent<>(eventType,this);
Event.fireEvent(this, event);
// Here I don't know how to get a value for target.
// Is there some standard target, which includes all FX components?
}
How the correctly throw this event?
Seems that I had a missunderstanding in how the triggering works in JavaFX. Now the most simple solution is:
#Override // Taken from Link
public void update(Observable observ, Object arg1) {
if (observ!=this.item)
{
LOGGER.error(new MLDConnectionException("Unexpected call of update() with observ = " + observ.toString()));
return;
}
// Build new Chidren list
try {
super.getChildren().removeIf((x) -> true); // empty list
super.getChildren().setAll(buildChildren(this));
} catch (MLDConnectionException e) {
LOGGER.error("Error when genereting children List: ", e);
}
}
public File addChild(String name) throws MLDException {
File newChild = itemManger.addChild(item, name);
update(this.item, null);
return newChild;
}

Xamarin Realm - when to close Realm

I have a Shared Project where I have changed the database to Realm instead of SQLite.
My problem is, if I close the Realm in my DatabaseManager, the result is removed. Therefore i have created a static singelton instance of the Realm, which all my DatabaseManager use. Now my app crash after short time on memory, and if i remove all my database-functions, it works.
I create my Realm-instance here:
public class RealmDatabase
{
private Realm mRealmDB;
public Realm RealmDB
{
get
{
if (mRealmDB == null || mRealmDB.IsClosed)
{
SetRealm ();
}
return mRealmDB;
}
}
static RealmDatabase cCurrentInstance;
public static RealmDatabase Current
{
get
{
if (cCurrentInstance == null)
cCurrentInstance = new RealmDatabase ();
return cCurrentInstance;
}
}
public RealmDatabase ()
{
}
private void SetRealm ()
{
var config = new RealmConfiguration ("DBName.realm", true);
mRealmDB = Realm.GetInstance (config);
}
public Transaction BeginTransaction ()
{
return RealmDB.BeginWrite ();
}
}
The I have my DatabaseManagler looking like this:
public class NewFreeUserManager
{
internal Realm RealmDB = RealmDatabase.Current.RealmDB;
static NewFreeUserManager cCurrentInstance;
public static NewFreeUserManager Current
{
get
{
if (cCurrentInstance == null)
cCurrentInstance = new NewFreeUserManager ();
return cCurrentInstance;
}
}
private NewFreeUserManager ()
{
}
internal bool Save (FreeUser freeuser)
{
try
{
using (var trans = RealmDB.BeginWrite ())
{
RealmDB.RemoveAll<FreeUser> ();
var fu = RealmDB.CreateObject<FreeUser> ();
fu = freeuser;
trans.Commit ();
}
return true;
}
catch (Exception e)
{
Console.WriteLine ("FreeUser save: " + e.ToString ());
return false;
}
}
internal FreeUser Get ()
{
return RealmDB.All<FreeUser> ().FirstOrDefault ();
}
}
Can anyone help me?
there are a few issues with your current setup that prevent you from persisting objects properly.
The first and very important one is that Realm instances are not thread-safe. That is, using them as singletons is strongly discouraged, unless you are certain that you'll never access them from another thread.
The second is more subtle, but in your save method you are calling:
var fu = RealmDB.CreateObject<FreeUser>();
fu = freeuser;
What it does is, effectively, you are creating an object in the Realm, and then assigning the variable to another object. This will not assign freeuser's properties to fu, it just replaces one reference with another. What you're looking for is Realm.Manage so your code should look like this:
using (var trans = RealmDB.BeginWrite())
{
RealmDB.Manage(freeuser);
trans.Commit();
}
Once you fix the second bug, you should be able to go back and close Realm instances when you don't need them anymore.

Updating a datatable in Wicket

We are developing a new application in Wicket and have run into a small problem.
What we do:
1) create a new SortableDataProvider
2) create a new DefaultDataTablePagingInBottom
3) create a new WebMarkupContainer
4) add the DefaultDataTablePagingInBottom to the WebMarkupContainer
5) create a new AjaxCheckBox
6) in the onUpdate of the AjaxCheckBox, add the WebMarkupContainer to the AjaxRequestTarget
7) set the SortableDataProvider to a new SortableDataProvider (with the updated query)
8) DefaultDataTablePagingInBottom.replaceWith(new DefaultDataTablePagingInBottom - with the new provider).
What happends:
1) Click the checkbox -> nothing happends.
2) Click it again -> crash: "Last cause: This method can only be called on a component that has already been added to its parent.
WicketMessage: Method onRequest of interface org.apache.wicket.behavior.IBehaviorListener targeted at org.apache.wicket.ajax.markup.html.form.AjaxCheckBox$1#1a2fefd on component [ [Component id = checkBox]] threw an exception"
3) Click back in the browser -> the list i filtered with the new provider.
Any ideas?
---EDIT---
Here's some code.
1) In the constructor of the WebPage:
model = new Model(projectPlannerService);
provider = new SortableProjectDataProvider(model, (WebSession) getSession(), isChecked);
table = new DefaultDataTablePagingInBottom("table", columns, provider, 50);
listContainer = new WebMarkupContainer("wmc");
listContainer.add(table);
add(listContainer.setOutputMarkupId(true));
/*
* checkbox för filtrering
*/
AjaxCheckBox checkBox = new AjaxCheckBox("checkBox", new Model()) {
#Override
protected void onUpdate(AjaxRequestTarget target) {
target.add(listContainer, "wmc");
isChecked = !isChecked;
provider = new SortableProjectDataProvider(model, (WebSession) getSession(), isChecked);
updateTable();
}
};
add(checkBox);
2) In updateTable():
table.replaceWith(new DefaultDataTablePagingInBottom("table", columns, provider, 50));
3) The SortableProjectDataProvider:
// Constructor
public SortableProjectDataProvider(IModel<?> model, WebSession webSession, boolean isChecked) {
this.model = model;
this.projectPlannerService = (ProjectPlannerService) model.getObject();
this.webSession = webSession;
setSort("customer", SortOrder.ASCENDING);
System.out.println("ischecked:" + isChecked);
if(!isChecked)
list = ((ProjectPlannerService) model.getObject()).findAllProjects();
else
list = ((ProjectPlannerService) model.getObject()).findAllActiveProjects();
System.out.println("size: " + list.size());
comparator = new ProjectComparator();
}
public Iterator<Project> iterator(int first, int count) {
Collections.sort(list, comparator);
if (first > list.size()) {
first = 0;
}
if (first + count > list.size()) {
return list.subList(first, list.size()).iterator();
} else {
return list.subList(first, first + count).iterator();
}
}
public IModel<Project> model(Project object) {
return new DetachableProjectModel((Project) object);
}
public int size() {
return list.size();
}
private class DetachableProjectModel extends LoadableDetachableModel {
private Long id;
#SpringBean
ProjectPlannerService projectPlannerService;
public DetachableProjectModel(Long id) {
Injector.get().inject(this);
if (id == null) {
throw new IllegalArgumentException();
}
this.id = id;
}
public DetachableProjectModel(Project project) {
this(project.getPk());
Injector.get().inject(this);
}
public int hashCode() {
return id.hashCode();
}
public boolean equals(final Object obj) {
if (obj == this) {
return true;
} else if (obj == null) {
return false;
} else if (obj instanceof DetachableProjectModel) {
DetachableProjectModel other = (DetachableProjectModel) obj;
return other.id == this.id;
}
return false;
}
protected Object load() {
return ((ProjectPlannerService) model.getObject()).findProjectById(id);
}
}
}
wicket:extend
-input wicket:id="checkBox" type="checkbox"- Show active -/input-
-div wicket:id="wmc"-
-table wicket:id="table"--/table-
-/div-
-/wicket:extend-
Thanks in advance!
/Andreas
By replacing the instance of your SortableProjectDataProvider with a new one you are making your life difficult. Instead of using the boolean isChecked in the constructor you could use an IModel<Boolean>. Assign the same instance of that model to your data provider and the check-box and you are done. No need to replace anything in onUpdate, add your listContainer to the AjaxRequestTarget and everything should just work...
e.g.
...
private IModel<Boolean> isCheckedModel = new Model<Boolean>(Boolean.FALSE);
...
provider = new SortableProjectDataProvider(model, (WebSession) getSession(), isCheckedModel);
...
AjaxCheckBox checkBox = new AjaxCheckBox("checkBox", isCheckedModel) {
#Override
protected void onUpdate(AjaxRequestTarget target) {
target.add(listContainer);
}
};
...
It is almost never a good idea to replace such things with new ones in Wicket. Encapsulate what changes in a model and change / replace the model's object. Every object that has a reference to that model can see the updated value or change it as needed.
Hope this helps.
Try this:
Wrong: target.add(listContainer, "wmc");
Right: target.add(listContainer);
Wrong; table.replaceWith(new DefaultDataTablePagingInBottom("table", columns, provider, 50));
Right: DefaultDataTablePagingInBottom tmp = new DefaultDataTablePagingInBottom("table", columns, provider, 50);
table.replaceWith(tmp);
table = tmp;
(You replace the DefaultDataTablePagingInBottom but not your reference.)
//olle

Resources