public void getSchoolClasses(ArrayList<SchoolClass>schoolClassesIds , final CompletionHandler completionHandler){
ParseQuery<ParseObject> query = ParseQuery.getQuery("schoolClasses");
query.whereContainedIn("objectId",schoolClassesIds);
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e==null){
for (int i =0 ; i < objects.size();i++){
SchoolClass schoolClass=(SchoolClass)objects.get(i);
schoolClass.getTeacher().fetchInBackground(new GetCallback<ParseObject>() {
#Override
public void done(ParseObject object, ParseException e) {
}
});
}
}else{
completionHandler.onError(e);
}
}
});
}
How do I know when all objects are finished being fetched and to fire the completion handler?
from your code i can understand that you have a School class and each school can have 1...many teachers.
For that structure you should go with pointers.
Pointers allows you to save one to many relation between 2 parse objects and the big advantage is that you can execute one api call to get all the data that you need so you will not need to call fetch in a loop which is a bad practice.
In order to use pointers you need to do the following:
Go to your School sub class and add setter and getter for teachers. The teachers will be of type List<{Teacher Sub Class object}>
Your query should look like the following now:
ParseQuery<ParseObject> query = ParseQuery.getQuery("schoolClasses");
query.whereContainedIn("objectId",schoolClassesIds);
query.include("teachers"); // this line will fetch also the teachers together with the school
In your query callback you can now access the teachers in the following way:
SchoolClass schoolClass=(SchoolClass)objects.get(i);
schoolClass.getTeachers();
Pointers also allows you to retrieve relation of relations by using dot notation inside the include function (e.g. "teachers.students" will bring all the teachers and all the students for each teacher). That is the reason why i told you to use Pointers.
You can read more about it in here
I also suggest you to read also on Sub Classing your parse objects. By looking at your code it looks like you are not really using it. Sub classing of parse objects allows you to keep your code more organized and also expose easy access to the parse objects.
Please read more about Subclass and how to use it in here
It's not mandatory only a recommendation :)
Related
i'm struggling with an efficient way to store requirements for a course inside of a course.
e.g.:
You can take part at course A when you passed B
You can take part at course A too when you passed course C and D
I hoped to be able to use a tree structure so I can easily check if a Person passed all requirements but because of the multiple options to pass requirements it is not possible.
Do you know any technique or Data structure to solve this?
A Course object has a list of Prerequisite objects, only one of which needs to be fulfilled. A Prerequisite object has a list of required Course objects, all of which needs to be passed for the Prerequisite object to be fulfilled.
public class Course {
private List<Prerequisite> prerequisites;
public boolean canBeTakenBy(Student student) {
return prerequisites.isEmpty() ||
prerequisites.stream().anyMatch(p -> p.isFulfilledBy(student));
}
}
public class Prerequisite {
private List<Course> requiredCourses;
public boolean isFulfilledBy(Student student) {
return requiredCourses.stream().allMatch(student::hasPassed);
}
}
public class Student {
private Set<Course> passedCourses;
public boolean hasPassed(Course course) {
return passedCourses.contains(course);
}
}
There are many ways you can accomplish what you want, personally, I think the easiest is having an ArrayList< ArrayList < Course > >
So for example, if you want to add a possible requirement option, you could create an ArrayList with the courses and push it to the end of the requirements.
Later to check it, just run the combinations, complexity shouldn't be a problem, if you have for example 10 possible requirements with 10 courses each, worst case scenario it would be a 10x10 loop, 10² to the computer is the same as nothing at all.
https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html
For an app I'm working on, I'm using Parse (www.parse.com) and I have two different pointer arrays in the _User class. That class contains two columns that I'm trying to include in my query: "following" and "friends".
My problem is that the result is always either null or empty pointers, depending on how I query it.
Parse mentions:
In some situations, you want to return multiple types of related objects in one query. You can do this with the include method.
However, using this include method causes the results to be null. This is my code:
ParseQuery<AAUser> query = ParseQuery.getQuery(AAUser.class);
query.include("following");
query.include("friends");
query.getInBackground(ParseUser.getCurrentUser().getObjectId, new GetCallback<AAUser>() {
#Override
public void done(AAUser user, ParseException e) {
if(e != null)
return;
Log.d(TAG, String.valueOf(user.getFollowing()));
}
});
user.getFollowing() alwas returns [null] whenever I include that field. However, if I don't include it, it returns an empty pointer as it should. [AALocation{id='iLUigvrvrc'}]
As you can see, I queried my subclassed AAUser class. I still get the same results by querying the ParseUser class so I don't see how subclassing made a difference.
How can I solve this issue? Is this a bug with the Parse SDK? I'm using version 1.7.1 of the Parse Android SDK.
.
I'm basically trying to refresh the current user data with these fields included but I see it's not working as it should...
And yes, I tried fetchInBackground() but it doesn't give me any ways to include those fields. My current workaround is to use the empty pointers and query all of them one by one but I find this to be an awful workaround... please halp.
Try this:
ParseQuery<ParseObject> query = ParseQuery.getQuery("_User");
query.include("following");
query.include("friends");
query.findInBackground(new FindCallback<ParseObject>()
{
public void done(List<ParseObject> followinglist, ParseException e)
{
for (ParseObject following : followinglist)
{
ParseObject follow = following.getParseObject("following");
ParseObject friend=following.getParseObject("friends");
}
}
});
I am working on an android app that loads in a list of students to display in a list based activity. There are two components to the app. There is a server which responds via xml with the list of current active students and a database on the app end which stores theses students with some details (name,age etc). I would like a way to sync these two data sources. When the app starts, I would like to check against the xml to see if students on the server were added/deleted and update the db accordingly.
I would be parsing the xml list into a student object at login. Is there any way to store/retrieve an entire object into an android supported db so I can do a direct comparison to see what to update/delete? It would end up being something like
if (serverStudent[0].name == dbStudent[0].name)
//overwrite dbStudent object with serverStudent fields
What is the most efficient/lightweight way to achieve object persistance and then comparison in Android?
Here's a method I have used in the past:
Anytime an object in the database is changed, use a timestamp column to store that time. When the app connects on startup, simply check each timestamp in the app db against the timestamp in the server db for each object. If the timestamps match, do nothing. If the timestamps don't match, retrieve the updated record from the server. Make sure you're using a detail enough timestamp (usually down to milli- or micro- seconds).
The nice thing about timestamps is that if you don't want the server data to override the app data, you could look at which is newer and keep that object if they've both been edited. Just adding some additional thoughts!
You can do something like this -
public class StudentRecord {
Vector<StudentData> studentDatas;
public StudentRecord()
{
studentDatas = new Vector<StudentData>();
}
public Vector<StudentData> getRecords() {
return studentDatas;
}
public void setRecords(Vector<StudentData> records) {
this.studentDatas = records;
}
public class StudentData
{
String name,Rollno;
public String getRollno() {
return Rollno;
}
public void setRollno(String rollno) {
Rollno = rollno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
When you get the vector object studentDatas you can do something like this -
for(Object object : record.getRecords())
{
data = (StudentData)object;
data.getRollno();
data.getName();
}
Check out these libraries:
http://www.datadroidlib.com/
https://github.com/octo-online/robospice
I believe both offer solutions for your situation.
Or you can roll your own solution... Basically you will want to create a service or asynctask to do the syncing, in your student object you can create a constructor that you can pass an id to and have it pull the appropriate record from your local db then make a comparison method that will update if newer information is available.
I'm not sure i understood your question correctly.But as far as i understand i would do something like this.
In server side send send Json array which holds json student objects.
In android side create similer Student class and override equals
method as you want.
Then for each student check with equals method whether they are
equals or not and take action accordingly.
If you want to make faster search in students object array then apply
hash map instead of arrays.
I'm trying to merge these three objects into a single complex object:
public class Person {
private String name;
private List<Event> events;
// getters and setters
}
public class Event {
private String name;
private List<Gift> gifts;
// getters and setters
}
public class Gift {
private String name;
private String recipient;// the name of the person
private String eventName;
// getters and setters
}
My goal is to save the Person object in MongoDB using Morphia and this how I want my document laid out. I've created a document builder, of sorts, that combines lists of each object. Each Person gets a list of all Events, but can only receive specific Gifts. While my document builder does create a document that Morphia can persist, only the Gifts of that last recipient (sort order) are inserted into the Events for all Persons. Though for the correct Events.
public void merge() {
for (Person person : listOfPersons) {
for (Event event : listOfEvents) {
// somePersonsGifts: a sublist of gifts based on Event and Person.
List<Gift> somePersonsGifts = new ArrayList<Gift>();
for (Gift gift : listOfGifts) {
if (person.getName().equals(gift.getRecipient()) && gift.getEventName().equals(event.getName())) {
somePersonsGifts.add(gift);
}
}
event.setGifts(somePersonsGifts);
}
person.setEvents(listOfEvents)
}
}
If I modify the code slightly to process one person at a time by removing the outer loop and having the method take an argument for specific index of the Persons list:
public void merge(int p) {
Person person = listOfPersons.get(p);
//...and so on
I get one complete Person object with the correct gifts. If try to feed the this modified version into a loop, the problem comes back. I've tried using regular for-loops and synchronized collections. I've tried using Google Guava's ImmutableArrayList and still no luck. I know the problem is that I'm changing the lists while accessing them but I can't find anyway around it. I wrote a DAO that uses the MongoDB driver directly and it works properly, but it's a lot more code and quite ugly. I really want this approach to work, the answer is in front of me but I just can't see it. Any help would be greatly appreciated.
Here is your problem:
List<Gift> somePersonsGifts = new ArrayList<Gift>();
....
event.setGifts(somePersonsGifts);
You add the gifts only for one person; if you want to aggregate all the gifts into the event, re-use the existing list.
I don't know anything about MongoDB or Morphia but I suspect the problem is your use of the setters event.setGifts(somePersonsGifts) and person.setEvents(events). Your code does not seem to merge the existing gift and event lists with the ones you are calculating further in the loop, which is how you would want it to behave (if I understand the question correctly).
You should retrieve the allready existing gift list (and event list too) instead of overwriting them with empty new ones.
I don't know if the method merge() is inside the list but I assume that since you are using the list events here
person.setEvents(events);
Maybe you meant
person.setEvents(listOfEvents)
Notice that you are adding all the events to each person. If all the persons went to all the events, it is unnecessary to have the events inside the person.
Main Goal : Select a school listed in the first datagrid, and display all the student records /details of that school in the next datagrid. But, since datagrid is editable and requirement mentions : "Use a Wrapper class around the object to get the data, set the same and save. Ensure wrapper is bindable to take into consideration the updates being made to datagrid text fields."
I have an object which is a type of a Data Access Objects i.e. DO.
mySchool:mySchoolDO.
The mySchoolDO is an actionScript class of following code :
public class mySchoolDO
{
public var schoolName:String;
public var schoolLocation:String;
public var schoolStudents:ArrayCollection;
// Array of myStudentDO instances
}
The above has an array collection of students called schoolStudents which accesses the myStudentDO.as class as described below.
myStudent:myStudentDO.
The myStudentDO.as is an actionScript class of following code :
public class myStudentDO implements IExternalizable
{
[Bindable] public var studentID: String;
[Bindable] public var studentCourses: Array
[Bindable] public var studentPhone:Number;
[Bindable] public var studentGender:Boolean;
public function readExternal(input:IDataInput):void {
studentID = SerializationUtils.readNullableString(input);
studentCourses = SerializationUtils.readNullableString(input);
studentPhone = SerializationUtils.readStringList(input);
studentGender = SerializationUtils.readNullableString(input);
}
In my main mxml application. I do the following :
1> Get all schools array. Instantiate a school object and get school data.
2> Using school object access all studentsDO data and store as an ARRAY OF OBJECTS.
private function availableSchools(schools:Array): void
{
mySchools=schools;
loadSchools();
}
private function loadSchools():void
{
for(var z:int =0; z
Once a school is clicked, an ItemClick Event is fired which takes the school and then displays all the school students data.
private function itemClickEvent(event:ListEvent):void
{
_school = event.currentTarget.selectedItem;
showSchoolStudents(_school);
}
private function showSchoolStudents(school:mySchoolDO)
{
for(var b:int=0; b<(school.schoolStudents).length;b++)
{
schoolDatagridProvider.push(school.schoolStudents[b]);
}
dgOfSchool.dataProvider = schoolDatagridProvider;
dgOfSchool.invalidateList();
}
The showSchoolStudents will display all the details of students on to the datagrid. But,
my datagrid is editable. And, I want to use WRAPPER CLASS around this object such that
a> I can retrieve individual values as present in studentsDO i.e. studentID, studentCourses, studentGender, studentPhone.
b> I shouldbe able to set the values as they are updated in the visual datagrid.
c> Finally save all the data and submit on submit click.
Please help with code. It will be highly appreciated.
Thanks.
Looks like you're really just starting out with Flex.
Suggestion: read the documentation. There's plenty of examples of the basic thing you're trying to do here which is to have an editable Grid that displays data coming from the server.
Some key concepts:
Make sure you're using an ArrayCollection as the dataProvider to the Grid, not an Array. ArrayCollections provide the change-notification machinery you'll invariably want with this use case.
Make sure your DO model classes are all Bindable. Looks like you're only making the Student properties bindable at the moment. Make the School bindable as well.
Make the reference from School to the collection of Students an ArrayCollection, not an Array.
Follow convention and use initial caps in Class names. i.e. MyStudentDO, MySchoolDO
Tell the DataGrid that you want to allow item editing.
But, in all seriousness, read the docs. There's plenty of examples available.