在嵌套循环+ vert.x + rx的情况下应如何处理结果处理程序

时间:2018-12-13 08:37:58

标签: rx-java rx-java2 vert.x

我有三种方法

1)获取模板

2)获取字段(模板ID)

3)获取字段元数据(字段ID)

方法调用的顺序是从上到下。 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()的时间。我的程序认为请求已完成。任何帮助将不胜感激。

谢谢

我已在vertx dev google组上发布了此问题。让我们看看是否有人回应there

1 个答案:

答案 0 :(得分:0)

使用rx时,应避免多次订阅,因为一旦订阅流结束,就不得不处理onError和OnSucess处理程序。处理该问题的责任应该在调用者身上。

我对rx的看法是,您正在处理逻辑流,其中同步逻辑中的每一步都会产生该流中的下一个操作所使用的结果。

因此,根据我对第一个示例中提供的代码的理解,您希望按名称查询模板,然后查询来自单独的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。 Single是一个值或一个错误。如果您需要返回多个值,则应该使用类似Observable的方法,或者像上面一样将所有内容组合到列表中。

作为用rx编写单元测试的奖励,我发现将lambda函数转换为方法引用使代码更易于单元测试!它将为您节省一些时间:)

对于其他两个示例,如果遵循相同的模式,那就应该行了!

让我知道您是否有任何疑问!