我喜欢Realm,易用性非常好,但有时候我很难找到一种方法来进行特定的查询。
假设我想查询一个表(RealmObject)并获得与列名(变量)匹配的所有结果,并且我希望每个id都是唯一的,并且也是给定变量名的最新记录。例如:
realm.where(RealmMessages.thisClass)
.distinctAsync(RealmMessages.FROM_TABLE)
.addChangeListener(listener)
这将获取每个唯一的'from'字段过滤的所有消息。但是这不起作用,因为我想要最新的'日期'和独特的'来'。
我将如何用领域做到这一点»?没有手动查询所有对象并且无法破坏“懒惰对象”的目的?
答案 0 :(得分:1)
您可以使用 “ realmQuery.findAll(... Sort [] ... Fields [] ...)”方法。你也可以 通过使用组和“或”进行多次查询。
您还可以使用“ distinct()”方法将“ id”重复1次
我不知道这对您是否有用,但是我做了一个类和一些方法,使我可以“对Realm进行快速和自动查询”。 这些是文件:
将其放入“ Realm Utils类”的同一包中(例如“ RealmHelper”,在其中实例化“ Realm”实例,并在其中具有查询领域ecc的所有方法...
public class RealmQueriesData<T> {
private List<QueryData> mQueries;
private QueryFind mFind;
private Class<T> mResultsClass;
/* START Factory Methods */
public static <T> RealmQueriesData<T> newInstanceFindEqualsTo(Class<T> resultsClass, String fieldName, Object value, Case mCase){
return new RealmQueriesData<>(
resultsClass,
QueryData.QUERY_EQUAL, fieldName, value, QueryFind.FIND_ALL, mCase
);
}
public static <T> RealmQueriesData<T> newInstanceCountEqualsTo(Class<T> resultsClass, String fieldName, Object value, Case mCase){
return new RealmQueriesData<>(
resultsClass,
new int[]{QueryData.QUERY_EQUAL, QueryData.QUERY_COUNT}, new String[]{fieldName, null},
new Object[]{value, null}, new Case[]{mCase, null}
);
}
public static <T> RealmQueriesData<T> newInstanceFindNotIn(Class<T> resultsClass, String fieldName, Object[] valuesIn){
return new RealmQueriesData<>(
resultsClass,
QueryData.QUERY_NOT_EQUAL, fieldName, valuesIn, QueryFind.FIND_ALL
);
}
/* END Factory Methods */
/* START Constructor Methods */
public RealmQueriesData(Class<T> resultsClass,
int[] queryTypes, String[] fieldNames, Object[] queryValues, Case[] mCases){
this.mResultsClass = resultsClass;
this.mQueries = new ArrayList<>();
for(int i = 0; i < queryTypes.length; i++){
int type = queryTypes[i];
String field = fieldNames[i];
Object value = queryValues[i];
Case mCase = mCases[i];
this.mQueries.add(
new QueryData(type, field, value, mCase)
);
}
}
public RealmQueriesData(Class<T> resultsClass, int queryType, String fieldName, Object[] queryValuesIn, int findType){
this.mResultsClass = resultsClass;
this.mQueries = new ArrayList<>();
this.mQueries.add(
new QueryData(queryType, fieldName, queryValuesIn)
);
this.mFind = new QueryFind(findType);
}
public RealmQueriesData(Class<T> resultsClass, int queryType, String fieldName, Object queryValue, int findType, Case mCase){
this.mResultsClass = resultsClass;
this.mQueries = new ArrayList<>();
this.mQueries.add(
new QueryData(queryType, fieldName, queryValue, mCase)
);
this.mFind = new QueryFind(findType);
}
public RealmQueriesData(Class<T> resultsClass){
this.mResultsClass = resultsClass;
this.mFind = new QueryFind();
}
/* END Constructor Methods */
/* START Getter & Setter Methods */
public List<QueryData> getQueries() {
return mQueries;
}
public void setQueries(List<QueryData> queries) {
this.mQueries = queries;
}
public QueryFind getFind() {
return mFind;
}
public void setFind(QueryFind find) {
this.mFind = find;
}
public Class<T> getResultsClass(){
return mResultsClass;
}
public void setResultsClass(Class<T> resultClass){
this.mResultsClass = resultClass;
}
/* END Getter & Setter Methods */
/* START Utils Methods */
public void addQuery(QueryData q){
mQueries.add(q);
}
public void addQuery(int type, String fieldName, Object value, Case mCase){
mQueries.add(new QueryData(type, fieldName, value, mCase));
}
public void addQuery(int type, String fieldName, Object value){
mQueries.add(new QueryData(type, fieldName, value));
}
public void addQuery(int type, String fieldName, Object value, Object valueTo){
mQueries.add(new QueryData(type, fieldName, value, valueTo));
}
public void addQuery(int type, String fieldName, Object[] valueIn){
mQueries.add(new QueryData(type, fieldName, valueIn));
}
public void addQuery(int type, String fieldName){
mQueries.add(new QueryData(type, fieldName));
}
/* END Utils Methods */
@Override
public String toString() {
return "RealmQueriesData{" +
"mQueries=" + mQueries.toString() +
", mFind=" + mFind.toString() +
", mResultsClass=" + mResultsClass.toString() +
'}';
}
}
class QueryData {
// QueryData Tipes
public static final int QUERY_NEGATION = 0x0;
public static final int QUERY_OR = 0x1;
public static final int QUERY_BEGIN_GROUP = 0x2;
public static final int QUERY_END_GROUP = 0x3;
public static final int QUERY_AVERAGE = 0x4;
public static final int QUERY_COUNT = 0x5;
public static final int QUERY_DISTINCT = 0x6;
public static final int QUERY_MAX = 0x7;
public static final int QUERY_MAX_DATE = 0x8;
public static final int QUERY_MIN = 0x9;
public static final int QUERY_MIN_DATE = 0xA;
public static final int QUERY_SUM = 0xB;
public static final int QUERY_EQUAL = 0xC;
public static final int QUERY_NOT_EQUAL = 0xD;
public static final int QUERY_CONTAINS = 0xE;
public static final int QUERY_IS_NULL = 0xF;
public static final int QUERY_NOT_NULL = 0x10;
public static final int QUERY_LESS = 0x11;
public static final int QUERY_GREATER = 0x12;
public static final int QUERY_GREATER_EQUAL = 0x13;
public static final int QUERY_LESS_EQUAL = 0x14;
public static final int QUERY_BETWEEN = 0x15;
public static final int QUERY_LIKE = 0x16;
public static final int QUERY_BEGINS = 0x17;
public static final int QUERY_ENDS = 0x18;
public static final int QUERY_IN = 0x19;
public static final int QUERY_IS_EMPTY = 0x1A;
public static final int QUERY_NOT_EMPTY = 0x1B;
int mType;
String mFieldName;
Object mValue;
Object mValueTo;
Object[] mValueIn;
Case mCase;
/* START Constructor Methods */
public QueryData(int type, String fieldName, Object value, Case mCase){
this.mType = type;
this.mFieldName = fieldName;
this.mValue = value;
this.mCase = mCase;
}
public QueryData(int type, String fieldName, Object value){
this.mType = type;
this.mFieldName = fieldName;
this.mValue = value;
}
public QueryData(int type, String fieldName, Object valueFrom, Object valueTo){
this.mType = type;
this.mFieldName = fieldName;
this.mValue = valueFrom;
this.mValueTo = valueTo;
}
public QueryData(int type, String fieldName, Object[] valueIn){
this.mType = type;
this.mFieldName = fieldName;
this.mValueIn = valueIn;
}
public QueryData(int type, String fieldName){
this.mType = type;
this.mFieldName = fieldName;
}
/* END Constructor Methods */
/* START Getter & Setter Methods */
public int getType() {
return mType;
}
public void setType(int type) {
this.mType = type;
}
public String getFieldName() {
return mFieldName;
}
public void setFieldName(String fieldName) {
this.mFieldName = fieldName;
}
public Object getValue(){
return mValue;
}
public void setValue(Object value){
this.mValue = value;
}
public Object getValueTo() {
return mValueTo;
}
public void setValueTo(Object valueTo) {
this.mValueTo = valueTo;
}
public Object[] getValueIn() {
return mValueIn;
}
public void setValueIn(Object[] valueIn) {
this.mValueIn = valueIn;
}
public Case getCase() {
return mCase;
}
public void setCase(Case mCase) {
this.mCase = mCase;
}
/* END Getter & Setter Methods */
@Override
public String toString() {
return "QueryData{" +
"mType=" + mType +
", mFieldName='" + mFieldName + '\'' +
", mValue=" + mValue +
", mValueTo=" + mValueTo +
", mValueIn=" + Arrays.toString(mValueIn) +
", mCase=" + mCase +
'}';
}
}
class QueryFind {
// QueryFind Types
public static final int FIND_ALL = 0x1;
public static final int FIND_ALL_SORTED_FIELD = 0x2;
public static final int FIND_ALL_SORTED_FIELD_SORT = 0x3;
public static final int FIND_ALL_SORTED_ARRAYS = 0x4;
int mType;
List<String> mSortFields;
List<Sort> mSorts;
boolean mRetAll;
/* START Constructor Methods */
public QueryFind(int type, List<String> sortFields, List<Sort> sorts, boolean retAll){
this.mType = type;
this.mSortFields = sortFields != null ? sortFields : new ArrayList<String>();
this.mSorts = sorts != null ? sorts : new ArrayList<Sort>();
this.mRetAll = retAll;
}
public QueryFind(int type, String sortField, Sort sort, boolean retAll){
this.mType = type;
this.mSortFields = new ArrayList<>();
this.mSortFields.add(sortField);
this.mSorts = new ArrayList<>();
this.mSorts.add(sort);
this.mRetAll = retAll;
}
public QueryFind(int type){
this.mType = type;
}
public QueryFind(){
this.mRetAll = true;
}
/* END Constructor Methods */
/* START Getter & Setter Methods */
public int getType() {
return mType;
}
public void setType(int type) {
this.mType = type;
}
public List<String> getSortFields() {
return mSortFields;
}
public void setSortFields(List<String> sortFields) {
this.mSortFields = sortFields;
}
public List<Sort> getSorts() {
return mSorts;
}
public void setSorts(List<Sort> sorts) {
this.mSorts = sorts;
}
public boolean getRetAll() {
return mRetAll;
}
public void setRetAll(boolean retAll) {
this.mRetAll = retAll;
}
/* END Getter & Setter Methods */
/* START Utils Methods */
public void addSort(String sortField, Sort sort){
mSortFields.add(sortField);
mSorts.add(sort);
}
/* END Utils Methods */
@Override
public String toString() {
return "QueryFind{" +
"mType=" + mType +
", mSortFields=" + mSortFields +
", mSorts=" + mSorts +
", mRetAll=" + mRetAll +
'}';
}
}
然后在您的“领域库文件”(例如“ RealmHelper”)中添加以下方法以通过向其传递“ RealmQueriesData”实例来进行查询:
public class RealmHelper {
protected Realm mRealm;
// Instance to have only 1 Realm open 4 every thread in your app
protected static RealmHelper mInstance;
[....]
/* START Realm Query Methods */
// Like the one below but return a List of objects and not a RealmResults
public <T> List<T> doQueryOnRealmAsList(RealmQueriesData filters){
return (List<T>) toList(doQueryOnRealm(filters));
}
// With this you can do every type of query which return values with
// "realmQuery.findAll()" methods
public <T> RealmResults<T> doQueryOnRealm(RealmQueriesData filters){
RealmResults<T> ret = null;
if(filters != null){
List<QueryData> queries = filters.getQueries();
QueryFind find = filters.getFind();
if(queries != null && queries.size() > 0) {
RealmQuery<T> realmQuery = mRealm.where(filters.getResultsClass());
for(QueryData query : queries){
if(query.getType() == QueryData.QUERY_DISTINCT){
ret = realmQuery.distinct(query.getFieldName());
} else {
realmQuery = getRealmQueryFromQueryData(realmQuery, query);
}
}
if(find != null) {
ret = getRealmQueryResults(realmQuery, find);
}
} else {
if(find != null && find.getRetAll()){
ret = (RealmResults<T>) findAllObject(filters.getResultsClass());
}
}
}
return ret;
}
// With this you can do every type of query which return a single value
// with "realmQuery.findFirst()" method.
public <T> T doQueryOnRealmSingleResult(RealmQueriesData filters){
T ret = null;
if(filters != null){
List<QueryData> queries = filters.getQueries();
QueryFind find = filters.getFind();
if(queries != null && queries.size() > 0){
RealmQuery<T> realmQuery = mRealm.where(filters.getResultsClass());
for(QueryData query : queries){
realmQuery = getRealmQueryFromQueryData(realmQuery, query);
}
ret = realmQuery.findFirst();
}
}
return ret;
}
// For queries whose return a Numerical value using SQL built-in functions
// like "max, count, min, average ..."
public Object doMathQueryOnRealm(RealmQueriesData filters){
Object ret = null;
if(filters != null){
List<QueryData> queries = filters.getQueries();
QueryData last = queries.get(queries.size() - 1);
queries.remove(last);
if(queries.size() > 0){
RealmQuery realmQuery = mRealm.where(filters.getResultsClass());
for(QueryData query : queries){
realmQuery = getRealmQueryFromQueryData(realmQuery, query);
}
ret = getMathQueryResult(realmQuery, last);
}
}
return ret;
}
private <T> RealmQuery<T> getRealmQueryFromQueryData(RealmQuery realmQuery, QueryData query){
String field; Object value; Case mCase;
switch(query.getType()){
case QueryData.QUERY_NEGATION:
realmQuery.not();
break;
case QueryData.QUERY_OR:
realmQuery.or();
break;
case QueryData.QUERY_BEGIN_GROUP:
realmQuery.beginGroup();
break;
case QueryData.QUERY_END_GROUP:
realmQuery.endGroup();
break;
case QueryData.QUERY_EQUAL:
field = query.getFieldName();
value = query.getValue();
if(value instanceof String){
mCase = query.getCase();
realmQuery.equalTo(field, value.toString(), mCase);
} else if(value instanceof Integer){
realmQuery.equalTo(field, (Integer) value);
} else if(value instanceof Double){
realmQuery.equalTo(field, (Double) value);
} else if(value instanceof Date){
realmQuery.equalTo(field, (Date) value);
}
break;
case QueryData.QUERY_NOT_EQUAL:
field = query.getFieldName();
value = query.getValue();
if(value instanceof String){
mCase = query.getCase();
realmQuery.notEqualTo(field, value.toString(), mCase);
} else if(value instanceof Integer){
realmQuery.notEqualTo(field, (Integer) value);
} else if(value instanceof Double){
realmQuery.notEqualTo(field, (Double) value);
} else if(value instanceof Date){
realmQuery.notEqualTo(field, (Date) value);
}
break;
case QueryData.QUERY_CONTAINS:
field = query.getFieldName();
value = query.getValue();
mCase = query.getCase();
if(mCase != null){
realmQuery.contains(field, value.toString(), mCase);
} else {
realmQuery.contains(field, value.toString());
}
break;
case QueryData.QUERY_IS_NULL:
realmQuery.isNull(query.getFieldName());
break;
case QueryData.QUERY_NOT_NULL:
realmQuery.isNotNull(query.getFieldName());
break;
case QueryData.QUERY_LESS:
field = query.getFieldName();
value = query.getValue();
if(value instanceof Integer){
realmQuery.lessThan(field, (Integer) value);
} else if(value instanceof Double){
realmQuery.lessThan(field, (Double) value);
} else if(value instanceof Date){
realmQuery.lessThan(field, (Date) value);
}
break;
case QueryData.QUERY_GREATER:
field = query.getFieldName();
value = query.getValue();
if(value instanceof Integer){
realmQuery.greaterThan(field, (Integer) value);
} else if(value instanceof Double){
realmQuery.greaterThan(field, (Double) value);
} else if(value instanceof Date){
realmQuery.greaterThan(field, (Date) value);
}
break;
case QueryData.QUERY_GREATER_EQUAL:
field = query.getFieldName();
value = query.getValue();
if(value instanceof Integer){
realmQuery.greaterThanOrEqualTo(field, (Integer) value);
} else if(value instanceof Double){
realmQuery.greaterThanOrEqualTo(field, (Double) value);
} else if(value instanceof Date){
realmQuery.greaterThanOrEqualTo(field, (Date) value);
}
break;
case QueryData.QUERY_LESS_EQUAL:
field = query.getFieldName();
value = query.getValue();
if(value instanceof Integer){
realmQuery.lessThanOrEqualTo(field, (Integer) value);
} else if(value instanceof Double){
realmQuery.lessThanOrEqualTo(field, (Double) value);
} else if(value instanceof Date){
realmQuery.lessThanOrEqualTo(field, (Date) value);
}
break;
case QueryData.QUERY_BETWEEN:
field = query.getFieldName();
value = query.getValue();
if(value instanceof Integer){
realmQuery.between(field, (Integer) value, (Integer) query.getValueTo());
} else if(value instanceof Double){
realmQuery.between(field, (Double) value, (Double) query.getValueTo());
} else if(value instanceof Date){
realmQuery.between(field, (Date) value, (Date) query.getValueTo());
}
break;
case QueryData.QUERY_LIKE:
field = query.getFieldName();
value = query.getValue();
mCase = query.getCase();
if(mCase != null){
realmQuery.like(field, value.toString(), mCase);
} else {
realmQuery.like(field, value.toString());
}
break;
case QueryData.QUERY_BEGINS:
field = query.getFieldName();
value = query.getValue();
mCase = query.getCase();
if(mCase != null){
realmQuery.beginsWith(field, value.toString(), mCase);
} else {
realmQuery.beginsWith(field, value.toString());
}
break;
case QueryData.QUERY_ENDS:
field = query.getFieldName();
value = query.getValue();
mCase = query.getCase();
if(mCase != null){
realmQuery.endsWith(field, value.toString(), mCase);
} else {
realmQuery.endsWith(field, value.toString());
}
break;
case QueryData.QUERY_IN:
field = query.getFieldName();
Object[] values = query.getValueIn();
if(values instanceof String[]){
realmQuery.in(field, (String[]) values);
} else if(values instanceof Integer[]){
realmQuery.in(field, (Integer[]) values);
} else if(values instanceof Double[]){
realmQuery.in(field, (Double[]) values);
} else if(values instanceof Date[]){
realmQuery.in(field, (Date[]) values);
}
break;
case QueryData.QUERY_IS_EMPTY:
realmQuery.isEmpty(query.getFieldName());
break;
case QueryData.QUERY_NOT_EMPTY:
realmQuery.isNotEmpty(query.getFieldName());
break;
}
return realmQuery;
}
private Object getMathQueryResult(RealmQuery realmQuery, QueryData query){
Object ret = null;
switch(query.getType()){
case QueryData.QUERY_AVERAGE:
ret = realmQuery.average(query.getFieldName());
break;
case QueryData.QUERY_COUNT:
ret = realmQuery.count();
break;
case QueryData.QUERY_MAX:
ret = realmQuery.max(query.getFieldName());
break;
case QueryData.QUERY_MAX_DATE:
ret = realmQuery.maximumDate(query.getFieldName());
break;
case QueryData.QUERY_MIN:
ret = realmQuery.min(query.getFieldName());
break;
case QueryData.QUERY_MIN_DATE:
ret = realmQuery.minimumDate(query.getFieldName());
break;
case QueryData.QUERY_SUM:
ret = realmQuery.sum(query.getFieldName());
break;
}
return ret;
}
private <T> RealmResults<T> getRealmQueryResults(RealmQuery<T> realmQuery, QueryFind find){
RealmResults<T> ret = null;
switch(find.getType()){
case QueryFind.FIND_ALL:
ret = realmQuery.findAll();
break;
case QueryFind.FIND_ALL_SORTED_FIELD:
ret = realmQuery.findAllSorted(find.getSortFields().get(0));
break;
case QueryFind.FIND_ALL_SORTED_FIELD_SORT:
ret = realmQuery.findAllSorted(find.getSortFields().get(0), find.getSorts().get(0));
break;
case QueryFind.FIND_ALL_SORTED_ARRAYS:
ret = realmQuery.findAllSorted(find.getSortFields().toArray(new String[]{}), find.getSorts().toArray(new Sort[]{}));
break;
}
return ret;
}
/* END Realm Query Methods */
}
通常要进行查询,我会在“ RealmQueriesData”类中创建一个新的“静态工厂方法”,这样我就可以通过调用1种方法对领域进行快速查询。
// GET all RealmObjects in your Realm by searching for all
// realm objects saved that have a specific value for a specific.
// Remember that the "field name" must be the "field attribute name" in the class
// and not the "SerializedName" label value!
// (As you can see in the method which do the query the "Case SENSITIVE / INSENSITIVE"
// is used only if you query a field which is a String type, if you are querying
// another type, like Integer/Double/Date, you can set the "CASE" to "null".
RealmResults<YourRealmObject> listCount = doQueryOnRealm(
RealmQueriesData.newInstanceFindEqualsTo(
YourRealmObject.class, "yourRealmObject Field Name", <field value of YourRealmObject>, <Case (SENSITIVE / INSENSITIVE)>
)
);
// Get a list of all RealmObjects whose have a specific value in a specific field
RealmResults<YourRealmObject> listObjs = doQueryOnRealm(
RealmQueriesData.newInstanceFindEqualsTo(
YourRealmObject.class, "Field Name of YourRealmObject", <Value of YourRealmObject field>, <Case (SENSITIVE / INSENSITIVE)>
)
);
// Like a COUNT query which look for all records that have a specific value
// in a specific column.
long count = (Long) doMathQueryOnRealm(
RealmQueriesData.newInstanceCountEqualsTo(
YourRealmObject.class, "Field Name of YourRealmObject", <Value of YourRealmObject field>, <Case (SENSITIVE / INSENSITIVE)>
)
);
我必须执行不同的方法来查询领域,因为领域查询可以返回不同的值,因此我必须对每种返回值执行3种方法:
- 多值返回(RealmResults / List)(findAll方法)
- 单值返回(T)(findFirst方法)
- 返回数值(对象)(最大,最小,计数,...查询)
我希望这对您有所帮助。 我没有很好地测试执行查询的方法,但是到目前为止,我对正在执行的查询没有发现任何问题。 如您所见,通过将RealmQueriesData实例传递给执行Realm查询的方法,我可以在Realm上进行查询,而仅通过将值传递给“ RealmQueriesData”类。 所以我个人喜欢使用这些类来进行领域查询,因为这是查询领域的一种非常快速的方法:)
如果您将使用这些类进行Realm查询,如果发现问题或对我的方法进行了一些很好的更改以提高其性能,请给我写信。 谢谢,祝您编码愉快!
再见! (z3r0)