2016-11-09 7 views
3

私は不思議ですが、パラメータを動的に入力できますか?例えば、私のようなオブジェクトいる:今、私は文をPreparedStatementsのパラメータを動的に設定する

class Fields { 
    private Integer id; 
    private String name; 

    public Fields(Integer id, String name) { 
    this.id = id; 
    this.name = name; 
    } 
    //Getter - setter here 
} 

を準備します

public void main() { 
    PreparedStatement ps = conn.PrepareStatement("SELECT * FROM table WHERE id = ? AND name = ?");` 
} 

その後、私はまあ...どのように、怠惰な私を呼び出す

Fields param = new Fields(2, "xxx");

を設定しましたPrepareStatementにparamを送信することはできますか

より良い私のポイントを説明するために

ps.setParameters(param.getAsArray())

、私は何かなどを作りたい::3210

または多分

for (Fields f: fieldList) { 
    sql += f + " = ?"; 
} 

恩赦上記のための私の行方不明 "AND"/"OR" 演算子コード。私の究極の目標は、部分的なフィールドだけを塗りつぶしてエンティティクラスを渡すことによって、フィールド全体と各パラメータを作成できるようにすることです。コードはnullフィールドをスキップし、塗りつぶしフィールドをパラメータとして配置します。

まあ、好奇心のためです。

あなたは

+0

AFAIKあなたは 'PreparedStatement'に渡すことができるものに関して制限があります。通常、データベースクエリで使用するタイプのみが許可されます。 int、varchar、blobなど 'Fields'クラスとは何ですか? –

+0

上記のfieldsクラスはStringに限られているため、あまり有用ではありません。また、あなたが参加していて、同じ変数が再利用された場合、同じFieldオブジェクトを再利用することはできませんでした。もちろん、PreparedStatementから拡張し、これを自分で実装することもできます。 –

+0

私のポイントをより良く説明するための情報を追加しました。つまり、エンティティオブジェクトから条件句を動的に作成し、フィールドとパラメータをエンティティオブジェクトから渡したいと思います。しかし、それだけでなく、いくつかの特定のクラスを作成し、関連フィールドを部分的に記入し、不要なものをスキップしてprepareStatementに渡すことができます。 – Magician

答えて

0

これは非常に粗い溶液です。私はまだフィールドのタイプStringを取得するためにすべてのフィールドを2回繰り返さなければならないという事実は嫌いですが、これはまだ非常に粗末なので、さらに精緻化してください。また、ps.setObject()がフェイルセーフの前にこれらのps.setSomething()パラメータを拡張する必要があります。また、これらの基準オブジェクトのスキャンをスキップし、実行するためにまっすぐに行くような基準なしにクエリを予測する必要があります。しかし、私はあなたがそのアイデアを得ることを望みます。 SELECT * FROM testTable WHERE id = ? と:

public static String addPrefix(String prefix, String field) { 
    return new StringBuilder(prefix) 
      .append(Character.toUpperCase(field.charAt(0))) 
      .append(field.substring(1)) 
      .toString(); 
} 

public static <T> List<T> query(Connection conn, T criteria, String operator) throws SQLException { 
    List<T> list = null; 
    Class<?> targetClass = criteria.getClass(); 
    if (targetClass.getAnnotation(Table.class) == null) throw new SQLException("ERROR: Table not defined at entity class " + targetClass.getName()); 
    StringBuilder SQL = new StringBuilder("SELECT * FROM ").append(targetClass.getAnnotation(Table.class).name()); 
    List<Object> parameters = new ArrayList<>(); 

    try { 
     Field[] fields = targetClass.getDeclaredFields(); 
     for (Field field : fields) { 
      if (field.getAnnotation(Column.class) == null) continue; 
       Method m = targetClass.getMethod(addPrefix("get", field.getName()).toString()); 
       Object o = m.invoke(criteria); 

       if (o == null) continue; 

       if (parameters.isEmpty()) SQL.append(" WHERE"); else SQL.append(operator); 
       SQL.append(" ").append(field.getAnnotation(Column.class).name()).append(" = ?"); 
       parameters.add(o); 
     } 

     try (Connection connection = IwiPrivate.getInstance().getConnection()) { 
      try (PreparedStatement ps = connection.prepareStatement(SQL.toString())) { 
       Integer x = 1; 
       for (Field field : fields) { 
        String type = field.getType().getName(); 
        Method m = targetClass.getMethod(addPrefix("get", field.getName())); 
        Object o = m.invoke(criteria); 

        if (o == null) continue; 
        if (type == "java.lang.String") ps.setString(x, (String) parameters.get(x)); 
        else if (type == "java.lang.Integer") ps.setInt(x, (Integer) parameters.get(x)); 
        else ps.setObject(x, parameters.get(x)); //Put more set traps here. 
       } 
       try (ResultSet rs = ps.executeQuery();) { 
        while (rs.next()) 
         list.add((T) Database.mapSingle(rs, targetClass)); 
       } 
      } 
     } 
    } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { 
     Logger.getLogger(QueryExperiment.class.getName()).log(Level.SEVERE, null, ex); 
    } 
    return list; 
} 

今、それを使用するために、単にこの

@Table(name = "testTable") 
public class Entity { 
    @Column(name = "id") 
    private Integer id; 

    @Column(name = "name") 
    private String name; 

    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

のようなエンティティ・オブジェクトを作成し、それはのようなSQLを作成します

public void testQuery() { 
    Entity criteria = new Entity(); 
    criteria.setId(7777); 
    try (Connection connection = yourDatabase.getConnection()) { 
     List<Entity> assets = QueryTest.query(connection, criteria, "AND"); 
    } catch (SQLException ex) { 
     Logger.getLogger(IwiPrivateTest.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

基準としてそれを置きますsetIntを使用して7777をパラメータとして送信

ORMを回避して簡単なクエリを作成したい場合は、この方法がうまくいくと思います。

1

あなたが直接フィールドクラスせずにパラメータの値を置くことができますありがとうございます。

ps.setParameters(2, "xxx"); 

これらを試してみてください。うまくいくと思います。

Field field1 = new Field(0,1,"id"); 
    Field field2 = new Field(1,"Nathan","name"); 

    List<Field> fields = new ArrayList<>(); 
    fields.add(field1); 
    fields.add(field2); 

    StringBuilder strBuilder = new StringBuilder("SELECT * FROM table WHERE "); 

    // Dynamically Construct your SQL Query String 
    for(int i = 0 ; i < fields.size() ; i++) { 
     String strTemp = " AND "; 
     String strTempEquals = " = ?"; 
     if(fields.size()-1 == i) { 
      strTemp = ";"; 
     } 
     strBuilder.append(fields.get(i).getColumnName()); 
     strBuilder.append(strTempEquals); 
     strBuilder.append(strTemp); 
    } 

     PreparedStatement ps = conn.PrepareStatement(strBuilder); 

    // Dynamically pass your values from your Field class to the parameters of PreparedStatement 
    for (Field tempField : fields) { 
     ps.setParameter(tempField.getIndex(),tempField.getValue()); 
    } 

私はあなたのフィールドクラスのいくつかの変更を行いました。

class Field { 
private Integer index; 
private Object value; 
private String columnName; 

// Constructor 
//Getters and Setter 
} 
+0

実際、私はそれを避けたいです。 – Magician

1

私はあなたが

class Fields { 
private Integer id; 
private String name; 
public Fields(int id,String name) 
{ 
    this.id=id; 
    this.name=name; 
    setParameter(); 
} 
public void setParameter() 
{ 
    PreparedStatement ps = conn.PrepareStatement("SELECT * FROM table WHERE id = ? AND name = ?"); 
    ps.setInt(1,id); 
    ps.setString(2,name); 
} 
} 
+1

それどころか、私は各パラメータにsetSomething()を指定したくありません。 – Magician

+0

uは休止状態/春を過ぎる必要があります –

+1

春が重過ぎ、Entityから直接条件を取得することはできません。 – Magician

0

のPreparedStatementがsetObject(int, java.lang.Object)メソッドを持っている必要があるか、これを願っています。このようにパラメータ化されたコンストラクタを使用してみてください。フィールドの配列/リストを受け入れ、sqlに名前を追加し、setObjectメソッドを使用してパラメータを設定するクラスまたはメソッド内で使用できます。

このアプローチはSQLインジェクション攻撃に対して非常に脆弱ですので、注意して使用してください。

+0

うーん...それは私にあるアイデアを与えます。私はすぐに何かを与えるでしょう。 – Magician

+0

本当の質問は私になぜこれが必要なのですか?あなたのテーブルに対応するPOJOクラスを作成し、対応するテーブルへ/からPOJOオブジェクトを読み書きするのはなぜですか? –

+0

私が言ったように、私はORMを使用しません。 JPAまたは休止状態または何か。私はちょうどそれらが好きではありません。彼らは重すぎるし、彼らは最適化が欠けている。したがって、私はデータベースサーバーから最適化することを好みます。私が必要とするのは、ビューまたはストアドプロシージャからの簡単な取得だけです。しかし、この質問は私の仕事をスピードアップすることができる単純な実験に過ぎませんでしたが、依然としてリソースについては軽視していました。 – Magician

関連する問題