In my app, I have a method that accepts an ArrayList of ID's and returns a RealmList of Machines belonging to these IDs.
public RealmList<Machine> getMachinesById(ArrayList<Long> machineIds) {
RealmList<Machine> machines = new RealmList<Machine>();
for (int i = 0; i < machineIds.size(); i++){
Machine m = getMachineById(machineIds.get(i));
if (m != null) {
machines.add(m);
}
}
return machines;
}
The getMachineById() function just finds the correct machine for a specific id.
I want to filter this output some more, however, when I try to get the RealmQuery by doing .where(), I get an Exception telling me I should put this RealmList in 'managed mode'.
Caused by: io.realm.exceptions.RealmException: This method is only available in managed mode
at io.realm.RealmList.where(RealmList.java:425)
I'm aware that I get this error because this list is standalone, and not managed by Realm.
It is probably important to add that this function will be called quite a lot, since it is triggered every time some list in my app refreshes. This would mean that (if possible) every time I'm creating a new managed RealmList.
My questions:
Is there any way to let this RealmList be managed by Realm?
If this is possible, is it a problem that this function is being called pretty often
Is there any other (preferred) way to achieve this (List of IDs > RealmResults/RealmQuery)
Is there any way to let this RealmList be managed by Realm?
Yes. There is. But the point of having RealmList is it should be a field of an RealmObjects. eg.:
public class Factory {
RealmList<Machine> machineList;
// setter & getters
}
Factory factory = new Factory();
RealmList<Machine> machineList = new RealmList<>();
// Add something to the list
factory.setMachines(machineList);
realm.beginTransaction();
Factory managedFactory = realm.copyToRealmOrUpdate(factory);
realm.commitTransaction();
Managed means it has be persisted Realm.
If this is possible, is it a problem that this function is being called pretty often
Depends, if you don't need to persist them again, see answer 3.
Is there any other (preferred) way to achieve this (List of IDs > RealmResults/RealmQuery)
In your case, maybe you can use ReaulResults instead? eg.:
RealmQuery<Machine> query = realm.where(Machine.class);
for (int i = 0; i < machineIds.size(); i++){
if (i != 0) query = query.or();
query = query.equalTo("id", machineIds.get(i));
}
RealmResults<Machine> machines = query.findAll();
Related
Given a query for members of a particular directory role, I would like to return a list of corresponding users. What I have is this:
IDirectoryObjectCollectionWithReferencesRequest request = graphServiceClient.directoryRoles(roleId).members().buildRequest();
IDirectoryObjectCollectionWithReferencesPage page = request.select(USER_FIELDS_TO_RETURN).get();
List<DirectoryObject> objects = page.getCurrentPage();
IDirectoryObjectCollectionWithReferencesRequestBuilder builder = page.getNextPage();
while (builder != null) {
request = builder.buildRequest();
page = request.select(USER_FIELDS_TO_RETURN).get();
objects.addAll(page.getCurrentPage());
builder = page.getNextPage();
}
return objects.stream().filter(o -> o.oDataType.equals("#microsoft.graph.user")).map(o -> new User()).collect(Collectors.toList());
The question lies in the return statement. Filter on only user objects (couldn't find a more elegant way of doing this than comparing the oDataType) and return the user object with the contents of o:
objects.stream().filter(o -> o.oDataType.equals("#microsoft.graph.user")).map(o -> {
// the only thing that I could think of is to do some weird
// serialization/deserialization logic here which is a bad solution
// for anything other than a small number of elements
}).collect(Collectors.toList());
what is the correct way of converting DirectoryObject to User
Microsoft Graph does not currently support this requirement.
If you're checking a specific directoryRole, you could come at this from the other direction. The /members endpoint does support filtering by member id:
v1.0/directoryRoles/{role-id}/members?$filter=id eq '{user-id}'
Please check the answers and workarounds provided in this thread. How to get admin roles that I am a member of, from Microsoft Graph using .Net Client SDK?
I know this is an old question, but I had the same problem and found a better solution.
You can actually convert it to a user after you have the list. So if you are iterating through the list:
var myDirectoryList = (List<DirectoryObject>)myRetrievedList;
foreach(var item in myDirectoryList)
{
var myUser = (User)item;
Console.WriteLine($"My name is {myUser.GivenName}");
}
Where DirectoryObject is Microsoft.Graph.DirectoryObject and User is Microsoft.Graph.User.
Just had the same problem, so, for anyone getting there, here is what i did (And i could not find any other simple solution...).
What you call "some weird serialization/deserialization logic" can actually be done this way using the DefaultSerializer :
private ISerializer serializer = new DefaultSerializer(new DefaultLogger());
...
objects.stream().filter(o -> o.oDataType.equals("#microsoft.graph.user")).map(o -> {
return serializer.deserializeObject(o.getRawObject().toString(), User.class)
}).collect(Collectors.toList());
I want save an object multiple times, the code below can not work:
for(int i = 0; i < 5; i++) {
repository.save(object);
}
Then I change the source to:
List<SomeObject> objectList = new ArrayList<>();
for(int i = 0; i < 5; i++) {
objectList.add(object);
}
repository.save(object);
But it also can not work, It only save the object one time to database.
Maybe because it point to one instance, but I want to know if there is an easy way to save an object multiple times?
Thank you!
It saves only 1 time the object because you are using the same instance every times.
So the first time you use object, so now it has an ID, then you use object again, but as we said it has an id so instead to save it, yours program update it inside you db.
For example if you do this:
for(int i = 0; i < 5; i++) {
repository.save(new Object());
}
Or if you have a list of Objects, like
List<SomeObject> objectList = new ArrayList<>();
for(int i = 0; i < 5; i++) {
objectList.add(object);
}
you could do this:
repository.saveAll(objectList);
Now you find 5 rows inside your table
I am not familiar with Spring data and might misunderstand the problem but generally there is no point to save the same object many times.
You need to explicitly create a clone/copy (or so) of an instance and save all these instances separately if you need multiple instances in database.
For example add creating new instance in a loop that saves the object.
Using the constructor, you can save same object multiple time:
Repository.save(new object(String name,String age));
At work, we have to generate a report for our client that changes its parameters several times during the week.
This report is generated from a single table on our database.
For example, imagine a table that has 100 columns and I have to generate a report with only 5 columns today, but tomorrow I have to generate with 95 of them.
With this in mind, I created a TO class with all the columns of the specified table and my query returns all columns (SELECT * FROM TABLE).
What I'm trying to create is a dynamic form to generate the report.
I first thought on create a simple frame with a list of the columns listed as check boxes and the user would select the columns that he wants (of course with a button to Select All and another to Deselect All).
As all of the columns have the same name as the attributes of the TO class, I developed the following code (I have Google this):
Class c = Test.class;
for(int i = 0; i < listOfAttributes.length; i++)
{
auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}
Is this the better way to do what I need to?
Thanks in advance.
Obs.: the getters of the TO class have the pattern "getAttribute_Name".
Note: This question is different from the one where the user is asking HOW to invoke some method given a certain name. I know how to do that. What I'm asking is if this is the better way to solve the problem I described.
My Java is a little more limited, but I believe that's about as good as you're going to get using reflection.
Class<?> c = Test.class;
for (String attribute : listOfAttributes) {
auxText += String.valueOf(c.getMethod("get" + attribute).invoke(this, null));
}
But since this sounds like it's from potentially untrusted data, I would advise using a HashMap in this case, with each method explicitly referenced. First of all, it explicitly states what methods can be dynamically called. Second, it's more type safe, and compile-time errors are way better than runtime errors. Third, it is likely faster, since it avoids reflection altogether. Something to the effect of this:
private static final HashMap<String, Supplier<Object>> methods = new HashMap<>();
// Initialize all the methods.
static {
methods.set("Foo", Test::getFoo);
methods.set("Bar", Test::getBar);
// etc.
}
private String invokeGetter(String name) {
if (methods.containsKey(name)) {
return String.valueOf(methods.get(name).get());
} else {
throw new NoSuchMethodException();
}
}
It might sound like a major DRY violation to do so, but the repetition at least makes sure you don't wind up with unrelated getters accidentally called.
Class c = Test.class;
for(int i = 0; i < listOfAttributes.length; i++)
{
auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}
You can do this somewhat more elegantly via Java Beans, the Introspector, and PropertyDescriptor, but it's a little more long-winded:
Map<String, Method> methods = new HashMap<>();
Class c = this.getClass(); // surely?
for (PropertyDescriptor pd : Introspector.getBeanInfo(c).getPropertyDescriptors())
{
map.put(pd.getName(), pd.getReadMethod();
}
//
for (int i = 0; i < listOfAttributes.length; i++)
{
Method m = methods.get(listOfAttributes[i]);
if (m == null)
continue;
auxText += String.valueOf(m.invoke(this, null));
}
Im trying to update multiple records via an ATG class extending GenericService.
However im running against a roadblock.
How do I do a multiple insert query where i can keep adding all the items / rows into the cached object and then do a single command sync with the table using item.add() ?
Sample code
the first part is to clear out the rows in the table before insertion happens (mighty helpful if anyone knows of a way to clear all rows in a table without having to loop through and delete one by one).
MutableRepository repo = (MutableRepository) feedRepository;
RepositoryView view = null;
try{
view = getFeedRepository().getView(getFeedRepositoryFeedDataDescriptorName());
RepositoryItem[] items = null;
if(view != null){
QueryBuilder qb = view.getQueryBuilder();
Query getFeedsQuery = qb.createUnconstrainedQuery();
items = view.executeQuery(getFeedsQuery);
}
if(items != null && items.length>0){
// remove all items in the repository
for(RepositoryItem item :items){
repo.removeItem(item.getRepositoryId(), getFeedRepositoryFeedDataDescriptorName());
}
}
for(RSSFeedObject rfo : feedEntries){
MutableRepositoryItem feedItem = repo.createItem(getFeedRepositoryFeedDataDescriptorName());
feedItem.setPropertyValue(DB_COL_AUTHOR, rfo.getAuthor());
feedItem.setPropertyValue(DB_COL_FEEDURL, rfo.getFeedUrl());
feedItem.setPropertyValue(DB_COL_TITLE, rfo.getTitle());
feedItem.setPropertyValue(DB_COL_FEEDURL, rfo.getPublishedDate());
RepositoryItem item = repo.addItem(feedItem) ;
}
The way I interpret your question is that you want to add multiple repository items to your repository but you want to do it fairly efficiently at a database level. I suggest you make use of the Java Transaction API as recommended in the ATG documentation, like so:
TransactionManager tm = ...
TransactionDemarcation td = new TransactionDemarcation ();
try {
try {
td.begin (tm);
... do repository item work ...
}
finally {
td.end ();
}
}
catch (TransactionDemarcationException exc) {
... handle the exception ...
}
Assuming you are using a SQL repository in your example, the SQL INSERT statements will be issued after each call to addItem but will not be committed until/if the transaction completes successfully.
ATG does not provide support for deleting multiple records in a single SQL statement. You can use transactions, as #chrisjleu suggests, but there is no way to do the equivalent of a DELETE WHERE ID IN {"1", "2", ...}. Your code looks correct.
It is possible to invoke stored procedures or execute custom SQL through an ATG Repository, but that isn't generally recommended for portability/maintenance reasons. If you did that, you would also need to flush the appropriate portions of the item/query caches manually.
I'm working with Flex 4 invoking webservices from JVM 1.6
I'm trying to make asynchronous calls to java to populate three comboboxes that will display country, states and cities, these three are related (master-slave relationship) but sometimes the calls are not met, or they are not completed, and I think this is because they are asynchronous, how can I be sure that I'm making the call to fill the next combobox when the master combobox (country) is filled?
protected function comboCountry_changeHandler(idCombo:String):void
{
selectedComboCountry= idCombo;
var countryId:String;
if(selectedComboCountry == comboCountry.id){
countryId = String(comboCountry.selectedItem.countryId);
}else if(selectedCombocountry == combocountrySuc.id){
countryId = String(comboCountrySuc.selectedItem.countryId);
}
obtainStatesResult.token = wsfacturas.obtainStates(countryId);
}
protected function obtainStatesResult_resultHandler(event:ResultEvent):void
{
var StateListVo:ArrayCollection = obtainStatesResult.token.result as ArrayCollection;
if(selectedComboCountry == "comboCountrySuc"){
StateListsSuc.removeAll();
CityListsSuc.removeAll();
for (var d:int = 0; d < StateListVo.length; d++){
var estSuc:State = StateListVo[d];
StateListsSuc.addItem(estSuc);
}
comboStateSuc.dataProvider = StateListsSuc;
}
else if(selectedCombocountry == "combocountry"){
StateListsEmp.removeAll();
CityListsEmp.removeAll();
for (var i:int = 0; i < StateListVo.length; i++){
var estEmp:State = StateListVo[i];
StateListsEmp.addItem(estEmp);
}
comboState.dataProvider = StateListsEmp;
} else {
for (var f:int = 0; f < StateListVo.length; f++){
var est:State = StateListVo[f];
StateListsSuc.addItem(est);
StateListsEmp.addItem(est);
}
comboState.dataProvider = StateListsEmp;
comboStateSuc.dataProvider = StateListsSuc;
}
}
Wouldn't it mean that you probably need to load the country and wait for change event on the country combobox to update state and so on? If you do that, you dont have to worry about asynchronicity of your requests? Otherwise, you might be able to use DataProviders and they might provide Event:Complete..
I am not sure though, I definitely am not an expert.. :)
You might want to give slightly more details in your question. But I am just playing with whatever details you have provided.
1_ First asynchronous calls never caused me any problem with dynamic data binding. Sometimes
a SOAP call can take reasonable amount of time, in that case, make sure to show a busy cursor till the web service call returns.
2_Combobox has always had problem with dynamic data binding. You can create a custom combobox that extends a combobox and override the setValue method Or Else you have to iterate over the dataProvider of the combobox and look for a match in the data field and then sets the combo box to that item.
So in summary, the problem mostly have to do with binding of the new data to the rendered combobox not asynchronous calls or any latency.