2

私は Java の初心者で、Map オブジェクトを含む DefaultMutableTreeNode クラスを作成したいと考えています。

私は、より一般的な TreeNode クラスを継承する TreeNodeMap クラスを作成しました。このクラスは、DefaultMutableTreeNode を継承します。

TreeNodeMap クラスには、かなり長いパラメータ リストを受け取るpopulateメソッドが含まれています。これらのパラメーターの一部を単一のオブジェクトに変換し、メソッドをオーバーロードして、最初の呼び出しで null のセットを渡す必要がないようにする (再帰的) ことで、メソッドの読みやすさを改善する予定です。

注:メソッドの詳細な説明を気にしない場合は、ここからコードに直接スキップしてください

最初に、子のみを含み、データを含まない空のノードを作成します。これが ROOT です。アイデアは、呼び出し元が「field_id」、「field_label」、「parent_id」列を持つ任意のクエリを渡すことができるメソッドを持つことです。最初の呼び出しでは、'parent_id が null' である Where 句を使用してクエリが渡されるため、親のないすべてのノードが取得されます。これらのノードはすべて ROOT ノードに追加されます。Resultset を繰り返し処理している間、各ノードのpopulateメソッドが呼び出され、parent_id = [現在のノード ID] である「Where 句」を渡して、そのノードのすべての子を取得します。これは、すべてのノードが階層で作成されるまで再帰的に発生します。

コード (JAVA は初めてなので、フィードバックをお待ちしております)

public void populate( boolean isRoot, String parentFieldId, String parentFieldLabel, String childFieldId, String childFieldLabel, 
            int parentId, String tableName, String whereClause, String orderByClause, String additionalColumns, List<Map<String, String>> queryParams) throws SQLException, Exception{
        ResultSet rs = null;
        Connection con = null;
        PreparedStatement ps = null;
        try{

            DBConnection dbConnection = new DBConnection("localhost", 3306, "root", "password", "test", DBDrivers.DBTYPE_MYSQL);
            con = dbConnection.getConnection();

            String treeNodeSql = "Select " + parentFieldId + ", " + parentFieldLabel + 
                                                ", " + childFieldId + ", " + childFieldLabel;
            if(additionalColumns != null && additionalColumns.trim().length() > 0)
                treeNodeSql +=  " ," + additionalColumns;

            treeNodeSql += " From " + tableName + " WHERE 1=1";

            if(whereClause != null && whereClause.trim().length() > 0 ){
                treeNodeSql += " AND " + whereClause;
            }

            if(isRoot){
                treeNodeSql += " AND " + parentFieldId + " is null";
            }else{
                if(parentFieldId == null || parentFieldId.trim().length() == 0)
                    throw new Exception(" The populate() method requires a parentId when isRoot is false.");
                treeNodeSql += " AND " + parentFieldId + " = ?";
            }
                //order clause append
            if(orderByClause != null && orderByClause.trim().length() > 0)
                treeNodeSql += " " + orderByClause;

                //prepare statement
             ps = con.prepareStatement(treeNodeSql); 
            int ixParam = 0;

                for(Map qParam : queryParams){
                    if(qParam.get("datatype") == "int"){
                        ps.setInt(++ixParam, Integer.parseInt((String) qParam.get("value")));
                    }else if(qParam.get("datatype") == "string"){
                        ps.setString(++ixParam, (String) qParam.get("value"));
                    }
                }

            out.println(treeNodeSql);
            if(parentId > 0){
                ps.setInt(queryParams.size()+1, parentId);
            }
            rs = ps.executeQuery();

            while(rs.next()){
                HashMap<String, Object> childNodeData = new HashMap<String, Object>(4);
                childNodeData.put("parentFieldId", parentFieldId);
                childNodeData.put("parentFieldIdValue", Integer.toString(rs.getInt(parentFieldId)));
                childNodeData.put("parentFieldLabel", parentFieldLabel);
                childNodeData.put("parentFieldLabelValue", rs.getString(parentFieldLabel));
                childNodeData.put("childFieldId", childFieldId);
                childNodeData.put("childFieldIdValue", Integer.toString(rs.getInt(childFieldId)));
                childNodeData.put("childFieldLabel", childFieldLabel);
                childNodeData.put("childFieldLabelValue", rs.getString(childFieldLabel));

                out.println("parentId: " + rs.getInt(parentFieldId)
                                + ", parentLabel: " + rs.getString(parentFieldLabel)
                                + ", childId: " + rs.getInt(childFieldId)
                                + ", childLabel: " + rs.getString(childFieldLabel));
                TreeNodeMap childNode = new TreeNodeMap(childNodeData);
                this.add(childNode);
                childNode.populate(false, parentFieldId, parentFieldLabel, childFieldId, childFieldLabel, rs.getInt(childFieldId), tableName, whereClause, orderByClause, additionalColumns, queryParams);
            }
        }catch(SQLException e){
            throw e;

        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            out.println(e.getCause());
            out.println(e.getMessage());
            e.printStackTrace();
            throw e;
        }finally {
            try { rs.close(); } catch (Exception e) {  }
            try { ps.close(); } catch (Exception e) {  }
            try { con.close(); } catch (Exception e) {  }
        }
    }   

メソッドの最初の呼び出しは次のようになります。

treeNode.populate(true, "supervisor_id", "supervisor", "employee_id", "employee", 0, "vw_employee", null, null, null, queryParams);

このアプローチで私が目にする問題は、DBがX回クエリされることであり、大きなデータセットではこれがいくつかの問題を引き起こすと思います。また、クエリごとに接続を開いています。そのため、(再帰呼び出しで) 作成されたメソッドに Connection を渡すことを考えましたが、適切に閉じる方法がわかりません。ノードが ROOT であるかどうかを確認する条件を記述してから、接続を閉じることができますが、その間にコードが失敗した場合はどうなりますか。

最後に私の質問: 1-これにアプローチする最良の方法は何ですか? 2-ツリーの作成中に1つの接続のみが開いたままになるように、接続を渡す必要がありますか? はいの場合、適切に閉じるにはどうすればよいですか。3- 結果セットを ArrayList にキャッシュして、代わりに使用する必要がありますか?

4

1 に答える 1

3

あなたのパフォーマンスの懸念は保証されるかもしれません。その代わり、

  1. TreeModelこの に示すように、 を実装しますFileTreeModel。このようにして、可視ノードのみを照会する必要があります。ここに関連する例があります。

  2. javax.sql.DataSourceではなく、 を渡しConnectionます。

  3. implements TreeModelキャッシュされたデータをカプセル化できるが、古いエントリを更新する手段も提供するクラス。キャッシュされた値を表示した後、ここSwingWorkerに示すように、 を使用してモデルを更新することを検討してください。の代わりに、 を見たいと思うかもしれません。List<Record>Map<PrimaryKey, Record>

于 2012-06-24T16:29:58.973 に答える