Получение данных из другого класса в одном запросе

Я создал приложение, использующее Parse. Мое приложение позволяет пользователям регистрироваться, входить в систему, а затем отправлять сообщения в облачную базу данных синтаксического анализа.
У меня есть два класса Parse: один называется User, а другой называется Posts. Пользователь состоит из ObjectId, имени пользователя и . пароль, а Сообщения состоят из ObjectId, текста и пользователь. Из которых user является указателем на ObjectId в классе User.

Я создал в своем приложении метод getData(), который содержит ParseQuery. Он запрашивает класс Posts и выбирает текст. поле и включает поле user. Затем запрос извлекает данные в список, а затем перебирает каждую строку списка, собирая строку из поля text, а затем добавляет ее в ListView в пользовательском интерфейсе. используя postList.add(textList.get(i).getString("text")); каждый раз, когда программа проходит через цикл.
В цикле находится еще один запрос, который запрашивает класс User, выбирает objectId, затем я добавляю в запрос ограничение, чтобы он извлекал только те данные, где поле objectId равно пользователю в классе Posts (я думаю).

ParseQuery<ParseObject> queryUser = ParseQuery.getQuery("User");
                        queryUser.selectKeys(Arrays.asList("objectId"));
                        queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));

Затем я хочу взять собранные данные имени пользователя, полученные запросом, поместить их в строку и отобразить на экране в тосте. Таким образом, метод getData() должен собирать все строки из поля текст и имя пользователя пользователя, который разместил это.

Проблема в том, что я не уверен, правильно ли я пытаюсь это сделать. Мое приложение выдает ошибку при выполнении этого фрагмента кода, поэтому я явно делаю что-то не так.

java.lang.IllegalStateException: ParseObject has no data for this key.  Call fetchIfNeeded() to get the data.
            at com.parse.ParseObject.checkGetAccess(ParseObject.java:3235)
            at com.parse.ParseObject.getString(ParseObject.java:2817)
            at com.text.parse.MainActivity$3.done(MainActivity.java:186)

Код в строке 186: queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));

Мои вопросы:
1. Правильно ли я пытаюсь это сделать?
2. Почему я получаю эту ошибку?

Код для метода getData():

public void getData() {

        final ArrayList<String> postList = new ArrayList<String>();
        final ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, R.layout.listview_row, postList);


        final ParseQuery<ParseObject> queryPosts = ParseQuery.getQuery("Posts");
        queryPosts.selectKeys(Arrays.asList("text"));
        queryPosts.include("user");
        queryPosts.addDescendingOrder("createdAt");
        queryPosts.setLimit(20);

        queryPosts.findInBackground(new FindCallback<ParseObject>() {

            @Override
            public void done(List<ParseObject> textList, ParseException e) {

                if (e == null) {
                    //query successful

                    for (int i = 0; i < textList.size(); i++) {

                        postList.add(textList.get(i).getString("text"));

                        ParseQuery<ParseObject> queryUser = ParseQuery.getQuery("User");
                        queryUser.selectKeys(Arrays.asList("objectId"));
                        queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));
                        queryUser.setLimit(20);

                        queryUser.findInBackground(new FindCallback<ParseObject>() {
                            @Override
                            public void done(List<ParseObject> userList, ParseException e) {

                                if (e == null) {

                                    String s = userList.get(0).getString("username").toString();

                                    Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
                                }

                                else {
                                    //query error

                                    Toast.makeText(MainActivity.this, "query error: " + e, Toast.LENGTH_LONG).show();
                                }
                            }
                        });
                    }

                    lvText.setAdapter(listAdapter);

                } else {
                    //query error

                    Toast.makeText(MainActivity.this, "query error: " + e, Toast.LENGTH_LONG).show();
                }

            }
        });
    }



Извините за длинный вопрос. Спасибо за любую помощь.


ОБНОВЛЕНИЕ:
Для тех, кто столкнулся с похожей проблемой, вот как я заставил ее работать:

public void getData() {

    final ArrayList<String> postList = new ArrayList<String>();
    final ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, R.layout.listview_row, postList);


    final ParseQuery<ParseObject> queryPosts = ParseQuery.getQuery("Posts");
    queryPosts.include("user");
    queryPosts.addDescendingOrder("createdAt");
    queryPosts.setLimit(20);

    queryPosts.findInBackground(new FindCallback<ParseObject>() {

        @Override
        public void done(List<ParseObject> textList, ParseException e) {

            if (e == null) {
                //query successful

                for (int i = 0; i < textList.size(); i++) {

                    postList.add(textList.get(i).getString("text"));


                    ParseObject po1 = textList.get(i);
                    ParseObject po2 = po1.getParseObject("user");
                    String username = po2.getString("username");

                    Toast.makeText(MainActivity.this, username, Toast.LENGTH_SHORT).show();
                }

                lvText.setAdapter(listAdapter);

            } else {
                //query error

                Toast.makeText(MainActivity.this, "query error: " + e, Toast.LENGTH_LONG).show();
            }

        }
    });
}


Вы просто включаете в запрашиваемый класс столбец, содержащий указатель на другой класс, который затем дает вам доступ ко всем столбцам данных во втором классе.


person Paul Alexander    schedule 24.03.2015    source источник


Ответы (1)


Этот метод, как показано, не делает ничего полезного:

ParseQuery<ParseObject> queryUser = ParseQuery.getQuery("User");
queryUser.selectKeys(Arrays.asList("objectId"));
queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));

Оператор selectKeys говорит ему возвращать только содержимое столбца objectId, которое вы передаете оператору whereEqualTo в качестве параметра... кажется глупым запускать запрос, чтобы получить значение, которое у вас уже есть!?. Я бы не стал использовать selectKeys, пока вы не подумаете, что вам нужно оптимизировать свои запросы. Единственное использование этого запроса — сообщить вам, является ли objectId допустимым, поскольку запрос вернет null, если он не является допустимым objectId для User.

Я надеюсь, что вы хотите получить больше информации о пользователе, поэтому, если вы удалите selectKeys, будут возвращены другие столбцы.

Тот факт, что fetchIfNeeded вызывает исключение из-за этой строки:

queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));

Это говорит о том, что textList.get(i).getString("user") не возвращает пользователю objectId. Если вместо этого возвращается username, как было предложено некоторыми из ваших других комментариев (здесь не уверен), вам нужно изменить эту строку кода, чтобы она читалась:

queryUser.whereEqualTo("username", textList.get(i).getString("user"));

Если у вас есть какие-то другие вопросы, вам нужно быть более точным в своих вопросах, поскольку не совсем понятно, о чем вы спрашиваете в данный момент.

person Timothy Walters    schedule 24.03.2015
comment
Спасибо за ответ. Я просто хочу, чтобы он делал то, что мне нужно, возвращал все сообщения и имя пользователя, принадлежащее каждому сообщению. Я не хотел задавать свой вопрос о том, как мне заставить это работать, поскольку я знаю, что люди здесь сходят с ума по этому поводу. - person Paul Alexander; 24.03.2015
comment
Если вы сделаете столбец user указателем на User в сообщении, то вы можете просто использовать postQuery.include("user"), чтобы сделать все свойства пользователя доступными. - person Timothy Walters; 24.03.2015
comment
Попробую позже, когда приду с работы :) - person Paul Alexander; 24.03.2015
comment
Ради интереса, если я включу указатель пользователя при первом запросе класса Posts, даст ли это мне доступ ко всем данным в моем классе User? - person Paul Alexander; 24.03.2015
comment
Да, пока вы вызываете include("user") в своем почтовом запросе, все пользовательские данные будут заполнены. - person Timothy Walters; 24.03.2015
comment
Итак, я мог бы запросить класс Posts, включить указатель пользователя в этот класс, а затем получить любое поле данных из моего класса User, потому что я включил поле указателя пользователя? Тогда это будет означать, что мне не понадобится второй запрос в цикле, не так ли? - person Paul Alexander; 24.03.2015
comment
просто чтобы убедиться, что здесь все ясно, когда вы говорите include(user), вы имеете в виду поле указателя пользователя в моем классе Posts, правильно? не класс пользователя - person Paul Alexander; 24.03.2015
comment
Правильно, вы добавляете это в запрос и включаете полное содержимое пользователя для этого сообщения. - person Timothy Walters; 25.03.2015