7

したがって、データベースから何かを返す簡単な関数があります。次に、 WHERE句にさまざまなパラメータを追加して、このクエリを変更できます。これを処理するための最もエレガントで効率的な方法は何でしょうか?

例:

    public static getUsers(int id, string username, string email) {

        Connection conn = null;
        PreparedStatement stmt = null;
        String sql = "";

        sql = "SELECT * FROM users " .........

そして、それは私がwhere句について混乱しているところです。私が何かをするなら

"WHERE id = ? AND username = ? AND email = ?";   

IDのみを使用し、ユーザー名や電子メールを使用せずにメソッドを呼び出すとどうなりますか?それは壊れて、私はそれを起こさせることができません。

また、のようなことをすると、インデックスの管理が難しくなりますがstmt.setInt(1, id)、ユーザー名でメソッドを呼び出したいだけで、そのIDがnullになると、NPEがスローされませんか?

私はJavaに慣れていないので、申し訳ありません...しかし、オーバーライドを使用する必要があると思いますか?条件文でwhere句を作成する必要がありますか?どんな助けでもいただければ幸いです。

ありがとう

4

8 に答える 8

2

Builder パターンを実装する SqlQuery クラスを作成します。これは、パターンの使用法を説明する優れた投稿です。

例:

public class SqlQuery {
    private StringBuilder tableQuery = new StringBuilder();
    private StringBuilder whereQuery = new StringBuilder();

    public SqlQuery(String selection, String table) {
        tableQuery.append("SELECT ").append(selection).append(" FROM ").append(table);
    }

    public SqlQuery addWhereClause(String parameter, String value) {
        if (whereQuery.length() == 0) {
            whereQuery.append(" WHERE ");
        }
        else {
            whereQuery.append(" AND ");
        }
        whereQuery.append(parameter).append(" = ").append(value);
        return this;
    }

    public String toString() {
        return tableQuery.toString() + whereQuery.toString();
    }
}

SqlQuery sqlQ = new SqlQuery("*", "users")
                  .addWhereClause("id", "2")
                  .addWhereClause("email", "test");
System.out.println(sqlQ);

これは以下を出力します:

SELECT * FROM users WHERE id = 2 AND email = テスト

于 2013-03-18T18:22:04.720 に答える
1

@ghdalum の優れたアイデアには、実際には PreparedStatement は含まれていません。以下は、PreparedStatement を生成するための彼のビルダーのアイデアの適応です。

public class UserQueryBuilder {

    private Connection conn;
    private StringBuilder query = new StringBuilder("SELECT * FROM users");
    private List<ValueSetter> valueSetters = new ArrayList<ValueSetter>();

    // callback interface for setting the column values
    private interface ValueSetter {
        void setValue(PreparedStatement ps);
    }

    // the caller is responsible for closing the connection afterwards
    public QueryBuilder(Connection conn) {
        this.conn = conn;
    }           

    public QueryBuilder byId(final Integer id) {
        appendSeparator();
        query.append("id = ?");
        valueSetters.add(new ValueSetter() {
            public void setValue(PreparedStatement ps) {
                ps.setInt(id);
            }
        });
        return this;
    }   

    public QueryBuilder byEmail(String email) {
        appendSeparator();
        query.append("email = ?");
        valueSetters.add(new ValueSetter() {
            public void setValue(PreparedStatement ps) {
                ps.setString(email);
            }
        });
        return this;
    }   

    public QueryBuilder byUsername(String username) {
        appendSeparator();
        query.append("username= ?");
        valueSetters.add(new ValueSetter() {
            public void setValue(PreparedStatement ps) {
                ps.setString(username);
            }
        });
        return this;
    }

    private void appendSeparator() {
        if (filterValues.size() == 0) {
            query.append(" WHERE ")
        }
        else {
            query.append(" AND ")
        }
    }

    public PreparedStatment build() {
        PreparedStatement ps = conn.prepareStatement(query.toString());
        for(ValueSetter valueSetter : valueSetters) {
            valueSetter.setValue(ps);
        }
        return ps;
    }
}

使用法:

PreparedStatement userQuery = new UserQueryBuilder(conn)
                              .byId("2")
                              .byEmail("test")
                              .build();
userQuery.execute();

(ところで、私はこのコードをテストしなかったので、タイプミスがあるかもしれません)

于 2013-03-19T08:43:04.620 に答える
0

これを実現するには、SQLクエリを動的に構築する必要があります。

public static getUsers(int id, string username, string email) {

    Connection conn = null;
    PreparedStatement stmt = null;
    String sql = "";

    sql = "SELECT * FROM users where id=? ";
    if (username != null)
      sql += " AND username=? ";
    if (email !=null)
      sql += " AND email=?";

    stmt = conn.prepareStatement(sql);
    stmt.setInt(1,id);
    if (username != null && email !=null)
    {
      stmt.setString(2,username);
      stmt.setString(3,email);
    }
    else if (username != null)
      stmt.setString(2,username);
    else if (email != null)
      stmt.setString(2,email);
于 2013-03-18T18:06:22.837 に答える
0

ifelseステートメントを記述します。

 if(username!=null)
 query=query+"username=?";

if(username!=null)
stmt.setInt(2, username)
于 2013-03-18T18:03:57.260 に答える
0

問題の解決策は次のようなものです。

public void getRecord(String id, String username, String email)
{
  String sql = " select * from users ";
  boolean isID , isUserName, isEmail;
  boolean isFirst = true;
  if (id!=null)
  {
     if ( isFirst)
     {
       sql = sql + " where";
       isFirst = false;
     }
     sql =  sql + " id = ?";
     isID = true;
  }
  if (username != null)
  {
     if ( isFirst)
     {
       sql = sql + " where";
       sql =  sql + " username = ?";
       isFirst = false;
     }
     else
     sql =  sql + " and username = ?";
     isUserName = true;
  }
  if (email != null)
  {
     if ( isFirst)
     {
       sql = sql + " where";
       sql = sql + " email = ?";
       isFirst = false;
     }
     else
     sql = sql + " and email = ?";
     isEmail = true;
  }
  PreparedStatement pst = con.prepareStatement(sql);
  int counter = 1;
  if (isID)
  pst.setString(counter++,id);
  if (isUserName)
  pst.setString(counter++,username);
  if (isEmail)
  pst.setString(counter++,email);
  //Then execute the query
  ResultSet rs = pst.executeQuery();
  .......
}
于 2013-03-18T18:11:41.230 に答える
0

私はこのようなことをし、受け入れるメソッドを作成し、List<ColumnNames>そのメソッドでプレースホルダーを列名に追加してすべての列名をループします。

public List<Something> method(List<Something> list){

String sql = "SELECT * FROM users WHERE "+ this.processPlaceHolders(list);

}

public String processPlaceHolders(List<Something> list) {
StringBuilder finalStr=new StringBuilder("");
for(int i=0;i<list.size(); i++){
if(i==list.size()-1){
finalStr.append(list.get(i)+"=" +"?"); 
}
else {
   finalStr.append(list.get(i)+"=" +"?,");
}
}
return finalStr.toString();
}
于 2013-03-18T18:04:11.440 に答える
0

これを試して:

public static getUsers(int id, String username, String email) {
        Connection conn = null;
        PreparedStatement stmt = null;
        String sql = "SELECT * FROM users WHERE id=? ";

        if (username != null && username.trim().length() != 0) sql = sql + " AND username=? "; 
        if (email != null && email.trim().length() != 0) sql = sql + " AND username=? ";

        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, id);

        if (username != null && username.trim().length() != 0) stmt.setString(2, username);
        if (email != null && email.trim().length() != 0) stmt.setString(3, email);
//.....
    }
于 2013-03-18T18:20:17.177 に答える
0

PreparedStatement を動的に構築する 1 つの非常に複雑なメソッドを記述する代わりに、入力の有効な組み合わせごとに個別のメソッドを記述することを検討する必要があります。次に、それぞれがその入力を簡単に検証でき、常に特定の PreparedStatement を使用します。これにより、将来の理解と保守が容易になるだけでなく、テストも容易になります。

既存の API との下位互換性が必要な場合は、必要にgetUsers(int id, string username, string email)応じてより単純なメソッドに委譲するメソッドを作成できます。

于 2013-03-18T19:08:19.793 に答える