Android领域查询

时间:2017-01-15 21:05:38

标签: android realm

我喜欢Realm,易用性非常好,但有时候我很难找到一种方法来进行特定的查询。

假设我想查询一个表(RealmObject)并获得与列名(变量)匹配的所有结果,并且我希望每个id都是唯一的,并且也是给定变量名的最新记录。例如:

 realm.where(RealmMessages.thisClass)
                .distinctAsync(RealmMessages.FROM_TABLE)
                .addChangeListener(listener)

这将获取每个唯一的'from'字段过滤的所有消息。但是这不起作用,因为我想要最新的'日期'和独特的'来'。

我将如何用领域做到这一点»?没有手动查询所有对象并且无法破坏“懒惰对象”的目的?

1 个答案:

答案 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)