Как обработчик результата должен обрабатываться в ситуации, когда у нас есть вложенный цикл + vert.x + rx - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть три метода

1) Получить шаблон

2) Получить поле (идентификатор шаблона)

3) Получить метаданные поля (идентификатор поля)

Порядок вызова методов сверху вниз.Метод getTemplate () возвращает один шаблон.Основываясь на ответе, я вызываю второй метод, чтобы получить связанные с ним поля.Я получаю несколько полей против шаблона.Я перебираю поля и ищу метаданные полей.Каждое поле имеет метаданные.

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

Вот мой код,

Первый метод

 public Single<Template> getByName(String lookupName) {
        return new AsyncResultSingle<Template>(resultHandler -> {
            jdbcClient.rxGetConnection().subscribe(connection -> {
                String sql = "SELECT * FROM template t WHERE t.name=?";
                JsonArray params = new JsonArray().add(lookupName);

                connection.rxQueryWithParams(sql, params).subscribe(resultSet -> {
                    List<JsonObject> rows = resultSet.getRows();
                    Template template = new Template();

                    for (JsonObject jsonObject : rows) {
                        template.id = jsonObject.getInteger("id");
                        template.name = jsonObject.getString("name", "");
                        template.column = jsonObject.getInteger("columns", -1);

                        Single<Map<Integer, TemplateField>> rxFields = templateFieldDao.getAllFields(template);
                        rxFields.subscribe(fields -> {
                            template.fields = fields; 
                             resultHandler.handle(Future.succeededFuture(template));  
                        }, failure -> {
                            resultHandler.handle(Future.failedFuture(failure));
                        });            
                    }

                }, onError -> {
                    resultHandler.handle(Future.failedFuture(onError));
                });
            }, onError -> {
                resultHandler.handle(Future.failedFuture(onError));
            });
        });
    }

Второй метод

 public Single<Map<Integer, TemplateField>> getAllFields(Template template) {

        return new AsyncResultSingle<Map<Integer, TemplateField>>(resultHandler -> {
            jdbcClient.rxGetConnection().subscribe(connection -> {
                String sql = "SELECT * from template_field as f where f.template_id=?";
                JsonArray params = new JsonArray().add(template.id);

                connection.rxQueryWithParams(sql, params).subscribe(resultSet -> {
                    Map<Integer, TemplateField> templateFieldMap = new HashMap<Integer, TemplateField>();
                    List<JsonObject> rows = resultSet.getRows();

                    for (JsonObject jsonObject : rows) {
                        TemplateField templateField = new TemplateField();   
                        templateField.id = jsonObject.getInteger("id");
                        templateField.name = jsonObject.getString("name");
                        templateField.order = jsonObject.getInteger("sort_order");
                        templateField.column_id = jsonObject.getInteger("column_id");
                        templateField.template_id = jsonObject.getInteger("template_id");

                        Single<Map<Integer, Metadata>> rxMetaData = metadata.getByFieldId(templateField);
                        rxMetaData.subscribe(fieldMetadata -> {
                            templateField.metadata = fieldMetadata;
                            templateFieldMap.put(templateField.id, templateField);
                             resultHandler.handle(Future.succeededFuture(templateFieldMap));
                        }, failure -> {
                            resultHandler.handle(Future.failedFuture(failure));
                        });
                    }

                }, onError -> {
                    resultHandler.handle(Future.failedFuture(onError));
                });
            }, onError -> {
                resultHandler.handle(Future.failedFuture(onError));
            });
        });

    }

Третий метод

public Single<Map<Integer, Metadata>> getByFieldId(TemplateField field) {
        return new AsyncResultSingle<Map<Integer, Metadata>>(resultHandler -> {
            jdbcClient.rxGetConnection().subscribe(connection -> {
                String sql = "SELECT m.id as id, m.name as name, m.value as value, m.isProperty as isValue FROM template_field_metadata as m WHERE m.template_field_id=?";
                JsonArray params = new JsonArray().add(field.id);
                Map<Integer, Metadata> metadataMap = new HashMap<Integer, Metadata>();

                connection.rxQueryWithParams(sql, params).subscribe(resultSet -> {
                    List<JsonObject> rows = resultSet.getRows();

                    for (JsonObject object : rows) {
                        Metadata metadata = new Metadata();
                        metadata.id = object.getInteger("id");
                        metadata.name = object.getString("name");
                        metadata.value = object.getString("value"); 
                        metadata.isValue = object.getBoolean("isValue"); 
                        metadataMap.put(metadata.id, metadata);
                    }

                    resultHandler.handle(Future.succeededFuture(metadataMap));
                }, onError -> {
                    resultHandler.handle(Future.failedFuture(onError));
                });
            }, onError -> {
                resultHandler.handle(Future.failedFuture(onError));
            });
        });

Я думаю, что время, когда я отправляю Future.succeeded () назад.Моя программа посчитала, что запрос был выполнен.Любая помощь будет оценена.

Спасибо,

Я разместил этот вопрос в группе Google Vertx Dev.Посмотрим, ответит ли кто-нибудь там .

1 Ответ

0 голосов
/ 13 декабря 2018

При работе с rx вам следует избегать многократной подписки, поскольку после подписки поток заканчивается и вы вынуждены обрабатывать обработчики onError и OnSucess.Ответственность за обработку должна быть на вызывающей стороне.

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

Итак, из моего понимания кода, представленного в первом примере, вы хотите запросить шаблоны по имени, а затем запросить оставшиеся поля из отдельного объекта DAO и отправить их вызывающей стороне.

См. Следующий код (я предоставил несколько комментариев, объясняющих его, дайте мне знать, если вам нужно больше объяснений):

public Single<List<Template>> getByName(String lookupName) {
        String sql = "SELECT * FROM template t WHERE t.name=?";
        JsonArray params = new JsonArray().add(lookupName);

        return jdbcClient.rxGetConnection()
        //you use flatmap to tranform a yield a observable
        .flatMap(connection ->  connection.rxQueryWithParams(sql, params))
        //you use a map when you need to transform a value into another value
        .map(resultSet -> resultSet.getRows()) //if this is supposed to only return one result you'll have have to throw an error
        .toObservable() //we need to say this if we plan on having multiple values
        .flatMap(Observable::from)//this would take the rows from the result set and convert it into an stream of json objects
        .flatMap(jsonObject -> {
            Template template = new Template();
            template.id = jsonObject.getInteger("id");
            template.name = jsonObject.getString("name", "");
            template.column = jsonObject.getInteger("columns", -1);
            return template
        })
        .flatMap(template -> templateFieldDao.getAllFields(template).toObservable())//It looks like your dao is yielding a single so we want observables until the next step
        .toList()//returns Single<List<Template>>
    }

Таким образом, абонентом этого метода будет тот, кто подпишетсяи обрабатывать значения.Я заметил небольшую проблему с вашим примером, когда вы могли бы завершить будущее несколько раз, что вызвало бы неожиданное поведение, потому что вы ожидали получить Single.Одиночный это либо одно значение, либо ошибка.Если вам нужно вернуть несколько значений, вы должны использовать что-то вроде Observable или объединить все в список, как я делаю выше.

В качестве бонуса при написании модульных тестов с помощью rx я обнаружил, что преобразование лямбда-функцийссылки на методы делают код намного проще для модульного тестирования!Это сэкономит вам немного времени спустя:)

Если вы последуете двум другим примерам и будете следовать этой же схеме, вам будет хорошо!

Дайте мне знать, если у вас есть какие-либо вопросы !!

...