私は新しいAndroid ORM Roomを使用しています。次の問題に直面しました。引数付きのORDER BYを使用するクエリは機能しません。
ORDER BYのパラメーターから入力されたフィールドを使用する場合、機能しません。それは何もソートしません。
@Query("SELECT * FROM User ORDER BY :orderBY ASC")
List<User> sortedFind(String orderBY);
ただし、クエリにORDER BY列を直接配置して結果を並べ替えると、期待どおりに機能します。
@Query("SELECT * FROM User ORDER BY name ASC")
List<User> sortedFind();
Android Roomのバグですか、それとも何か間違っていますか?
何が起こっているのか
パラメーターとして@Dao
メソッドに渡すことができる値は、クエリ文字列ではなく値のみです。この理由(私は信じています)は、SQLインジェクションの問題を防ぐためです。
なぜそうなのか
たとえば、クエリSELECT * emails WHERE uid = ?
を実行してから、値を"1 OR WHERE isAdmin = true"
に設定します。これにより、ユーザーはデータベースで独自のカスタムクエリを実行し、必要な処理を実行できます。
私の解決策
私もこの問題に遭遇しました。ここに私の solution へのリンクがあります。
私のソリューションには2つの部分があります。最初にDynamicQueryservice
が入力に基づいてクエリ文字列と値配列を生成し、次に生のクエリを実行してCursor
を返します。第二に、Cursor2POJO
マッパーなので、クラスのカーソルマッピングを何度も記述したり、潜在的なメンテナンスの問題を導入したりする必要がありません。クラスに注釈を追加するだけで(部屋の列名と一致する)、libが残りを処理します。
カーソルマッパーを独自の library に分割しました。ご参考までに、お気軽に使用してください(readmeが明確でない場合や、コメントにバグがある場合は作成してください) 。
追伸私のライブラリは、注釈が現在RetentionPolicy.CLASSとして設定されているため、リフレクションからアクセスできないため、Room @ColumnInfoを使用して列名を取得できません。 (Google課題トラッカーに追加 https://issuetracker.google.com/issues/6372094 )
ランタイムクエリには@RawQuery
アノテーションとSupportSQLiteQuery
クラスを使用する必要があります
ダオで:
@RawQuery
List<Objects> runtimeQuery(SupportSQLiteQuery sortQuery);
データを取得するには:
String query ="SELECT * FROM User ORDER BY " + targetField + " ASC";
List<Objects> users = appDatabase.daoUser().runtimeQuery(new SimpleSQLiteQuery(query));
いずれかの列の名前を参照して、データを昇順でのみ配置できます。プログラムでDaoメソッドに値を渡すことはできません
問題は、SQLステートメントの一部を渡すことですが、Roomはそれをクエリパラメーターのように扱います。
必要に応じて、SQLiteが管理するAndroidプラットフォームおよびサポートしている状況のようなオープンソースライブラリであるKripton Persistence Libraryを使用してみてください。
KriptonはDAOパターンでも動作するため、コンセプトは非常に似ています。ニーズに合った例を書くだけです:
モデルクラスがある場合:
@BindType
public class User {
public long id;
public String name;
public String username;
public String email;
public Address address;
public String phone;
public String website;
public Company company;
}
dAO定義:
@BindDao(User.class)
public interface UserDao {
@BindSqlInsert
void insert(User bean);
@BindSqlSelect
List<User> sortedFind(@BindSqlDynamicOrderBy String orderBy);
}
およびデータソース定義:
@BindDataSource(daoSet={UserDao.class}, fileName = "kripton.quickstart.db", generateAsyncTask = true)
public interface QuickStartDataSource {
}
Kriptonは、コンパイル時にすべてのコードがデータベースで動作するために必要なものを生成します。 Kriptonでタスクを達成するには、次のようなコードを記述する必要があります。
BindQuickStartDataSource ds = BindQuickStartDataSource.instance();
// execute operation in a transaction
ds.execute(new BindQuickStartDataSource.SimpleTransaction() {
@Override
public boolean onExecute(BindQuickStartDaoFactory daoFactory) throws Throwable
{
UserDaoImpl dao = daoFactory.getUserDao();
dao.sortedFind("name asc");
return true;
}
});
上記のコードを実行すると、logcatで生成されたログが表示されます。
database OPEN READ_AND_WRITE_OPENED (connections: 1)
SELECT id, name, username, email, address, phone, website, company FROM user ORDER BY name asc
Rows found: 0
database CLOSED (READ_AND_WRITE_OPENED) (connections: 0)
クリプトンは、明らかに静的順序とその他の多くの機能をサポートしています(2015年に開発を開始しました)。
Kripton Persistence Libraryの詳細: