QueryDsl avoiding multiple if blocks











up vote
2
down vote

favorite
1












Currently I am using Query DSL in my Java(with JPA) EE project. I recieve a filterObject from UI as json with all the filters. My FilterObject looks like this



public class FilterObject {

private String name;
private List<Status> status;
private String module;
private List<Source> source;
......
}


And in my service class I have something like this



 public List<MyModel> findByFilter(FilterObject filterObject) {
BooleanBuilder builder = new BooleanBuilder();

QMyModel mymodel= QMyModel.myModel;

if(filterObject.getName() != null) {
builder.and(mymodel.name.contains(filterObject.getName()));
}
if(! CollectionUtils.isEmpty(filterObject.getStatus())) {
builder.and(mymodel.status.in(filterObject.getStatus()));
}
...............
...............
}


And finally I have this



JPAQuery<MyModel> query = new JPAQuery<>(getEntityManager());
List<MyModel> myModels = query.from(QMyModel.mymodel).where(builder).fetch();


EDIT:



/**
* QMyModel is a Querydsl query type for MyModel
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QMyModel extends EntityPathBase<MyModel> {

private static final long serialVersionUID = 1041638507L;

private static final PathInits INITS = PathInits.DIRECT2;

public static final QMyModel myModel = new QMyModel("myModel");

public final StringPath name = createString("name");

public final EnumPath<Status> status = createEnum("status", Status.class);

public final StringPath module = createString("module");

........
.......
}


All these work. But my FilterObject is growing and has more than 10 fields. So I have like 10 If blocks in my service class method. Is there a better way to do this where I could avoid so many if blocks.










share|improve this question
























  • There is support for auto-binding a predicate however you would need to switch to using a query string e.g. /orders?status=PAID&status=DELIVERED&customer.surname=smith. More details here: spring.io/blog/2015/09/04/…
    – Alan Hay
    Nov 8 at 9:36










  • @AlanHay thanks for the reply. I know about QueryDslPredicate but that is in spring. But I am not using spring.
    – pvpkiran
    Nov 8 at 9:59












  • Can you post the class QMyModel ?
    – Benoit
    Nov 8 at 10:22










  • @Benoit QMyModel is the autogenerated class of MyModel @Entity class
    – pvpkiran
    Nov 8 at 11:06






  • 1




    You could possibly look at some kind of reflection based solution. Iterate the fields of the filter and return the corresponding boolean condition. You could use a custom annotation on the fields to allow for more flexible binding.
    – Alan Hay
    Nov 8 at 12:09

















up vote
2
down vote

favorite
1












Currently I am using Query DSL in my Java(with JPA) EE project. I recieve a filterObject from UI as json with all the filters. My FilterObject looks like this



public class FilterObject {

private String name;
private List<Status> status;
private String module;
private List<Source> source;
......
}


And in my service class I have something like this



 public List<MyModel> findByFilter(FilterObject filterObject) {
BooleanBuilder builder = new BooleanBuilder();

QMyModel mymodel= QMyModel.myModel;

if(filterObject.getName() != null) {
builder.and(mymodel.name.contains(filterObject.getName()));
}
if(! CollectionUtils.isEmpty(filterObject.getStatus())) {
builder.and(mymodel.status.in(filterObject.getStatus()));
}
...............
...............
}


And finally I have this



JPAQuery<MyModel> query = new JPAQuery<>(getEntityManager());
List<MyModel> myModels = query.from(QMyModel.mymodel).where(builder).fetch();


EDIT:



/**
* QMyModel is a Querydsl query type for MyModel
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QMyModel extends EntityPathBase<MyModel> {

private static final long serialVersionUID = 1041638507L;

private static final PathInits INITS = PathInits.DIRECT2;

public static final QMyModel myModel = new QMyModel("myModel");

public final StringPath name = createString("name");

public final EnumPath<Status> status = createEnum("status", Status.class);

public final StringPath module = createString("module");

........
.......
}


All these work. But my FilterObject is growing and has more than 10 fields. So I have like 10 If blocks in my service class method. Is there a better way to do this where I could avoid so many if blocks.










share|improve this question
























  • There is support for auto-binding a predicate however you would need to switch to using a query string e.g. /orders?status=PAID&status=DELIVERED&customer.surname=smith. More details here: spring.io/blog/2015/09/04/…
    – Alan Hay
    Nov 8 at 9:36










  • @AlanHay thanks for the reply. I know about QueryDslPredicate but that is in spring. But I am not using spring.
    – pvpkiran
    Nov 8 at 9:59












  • Can you post the class QMyModel ?
    – Benoit
    Nov 8 at 10:22










  • @Benoit QMyModel is the autogenerated class of MyModel @Entity class
    – pvpkiran
    Nov 8 at 11:06






  • 1




    You could possibly look at some kind of reflection based solution. Iterate the fields of the filter and return the corresponding boolean condition. You could use a custom annotation on the fields to allow for more flexible binding.
    – Alan Hay
    Nov 8 at 12:09















up vote
2
down vote

favorite
1









up vote
2
down vote

favorite
1






1





Currently I am using Query DSL in my Java(with JPA) EE project. I recieve a filterObject from UI as json with all the filters. My FilterObject looks like this



public class FilterObject {

private String name;
private List<Status> status;
private String module;
private List<Source> source;
......
}


And in my service class I have something like this



 public List<MyModel> findByFilter(FilterObject filterObject) {
BooleanBuilder builder = new BooleanBuilder();

QMyModel mymodel= QMyModel.myModel;

if(filterObject.getName() != null) {
builder.and(mymodel.name.contains(filterObject.getName()));
}
if(! CollectionUtils.isEmpty(filterObject.getStatus())) {
builder.and(mymodel.status.in(filterObject.getStatus()));
}
...............
...............
}


And finally I have this



JPAQuery<MyModel> query = new JPAQuery<>(getEntityManager());
List<MyModel> myModels = query.from(QMyModel.mymodel).where(builder).fetch();


EDIT:



/**
* QMyModel is a Querydsl query type for MyModel
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QMyModel extends EntityPathBase<MyModel> {

private static final long serialVersionUID = 1041638507L;

private static final PathInits INITS = PathInits.DIRECT2;

public static final QMyModel myModel = new QMyModel("myModel");

public final StringPath name = createString("name");

public final EnumPath<Status> status = createEnum("status", Status.class);

public final StringPath module = createString("module");

........
.......
}


All these work. But my FilterObject is growing and has more than 10 fields. So I have like 10 If blocks in my service class method. Is there a better way to do this where I could avoid so many if blocks.










share|improve this question















Currently I am using Query DSL in my Java(with JPA) EE project. I recieve a filterObject from UI as json with all the filters. My FilterObject looks like this



public class FilterObject {

private String name;
private List<Status> status;
private String module;
private List<Source> source;
......
}


And in my service class I have something like this



 public List<MyModel> findByFilter(FilterObject filterObject) {
BooleanBuilder builder = new BooleanBuilder();

QMyModel mymodel= QMyModel.myModel;

if(filterObject.getName() != null) {
builder.and(mymodel.name.contains(filterObject.getName()));
}
if(! CollectionUtils.isEmpty(filterObject.getStatus())) {
builder.and(mymodel.status.in(filterObject.getStatus()));
}
...............
...............
}


And finally I have this



JPAQuery<MyModel> query = new JPAQuery<>(getEntityManager());
List<MyModel> myModels = query.from(QMyModel.mymodel).where(builder).fetch();


EDIT:



/**
* QMyModel is a Querydsl query type for MyModel
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QMyModel extends EntityPathBase<MyModel> {

private static final long serialVersionUID = 1041638507L;

private static final PathInits INITS = PathInits.DIRECT2;

public static final QMyModel myModel = new QMyModel("myModel");

public final StringPath name = createString("name");

public final EnumPath<Status> status = createEnum("status", Status.class);

public final StringPath module = createString("module");

........
.......
}


All these work. But my FilterObject is growing and has more than 10 fields. So I have like 10 If blocks in my service class method. Is there a better way to do this where I could avoid so many if blocks.







java jpa java-8 querydsl






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 8 at 18:04









Benoit

1,8031822




1,8031822










asked Nov 8 at 9:24









pvpkiran

11.2k42038




11.2k42038












  • There is support for auto-binding a predicate however you would need to switch to using a query string e.g. /orders?status=PAID&status=DELIVERED&customer.surname=smith. More details here: spring.io/blog/2015/09/04/…
    – Alan Hay
    Nov 8 at 9:36










  • @AlanHay thanks for the reply. I know about QueryDslPredicate but that is in spring. But I am not using spring.
    – pvpkiran
    Nov 8 at 9:59












  • Can you post the class QMyModel ?
    – Benoit
    Nov 8 at 10:22










  • @Benoit QMyModel is the autogenerated class of MyModel @Entity class
    – pvpkiran
    Nov 8 at 11:06






  • 1




    You could possibly look at some kind of reflection based solution. Iterate the fields of the filter and return the corresponding boolean condition. You could use a custom annotation on the fields to allow for more flexible binding.
    – Alan Hay
    Nov 8 at 12:09




















  • There is support for auto-binding a predicate however you would need to switch to using a query string e.g. /orders?status=PAID&status=DELIVERED&customer.surname=smith. More details here: spring.io/blog/2015/09/04/…
    – Alan Hay
    Nov 8 at 9:36










  • @AlanHay thanks for the reply. I know about QueryDslPredicate but that is in spring. But I am not using spring.
    – pvpkiran
    Nov 8 at 9:59












  • Can you post the class QMyModel ?
    – Benoit
    Nov 8 at 10:22










  • @Benoit QMyModel is the autogenerated class of MyModel @Entity class
    – pvpkiran
    Nov 8 at 11:06






  • 1




    You could possibly look at some kind of reflection based solution. Iterate the fields of the filter and return the corresponding boolean condition. You could use a custom annotation on the fields to allow for more flexible binding.
    – Alan Hay
    Nov 8 at 12:09


















There is support for auto-binding a predicate however you would need to switch to using a query string e.g. /orders?status=PAID&status=DELIVERED&customer.surname=smith. More details here: spring.io/blog/2015/09/04/…
– Alan Hay
Nov 8 at 9:36




There is support for auto-binding a predicate however you would need to switch to using a query string e.g. /orders?status=PAID&status=DELIVERED&customer.surname=smith. More details here: spring.io/blog/2015/09/04/…
– Alan Hay
Nov 8 at 9:36












@AlanHay thanks for the reply. I know about QueryDslPredicate but that is in spring. But I am not using spring.
– pvpkiran
Nov 8 at 9:59






@AlanHay thanks for the reply. I know about QueryDslPredicate but that is in spring. But I am not using spring.
– pvpkiran
Nov 8 at 9:59














Can you post the class QMyModel ?
– Benoit
Nov 8 at 10:22




Can you post the class QMyModel ?
– Benoit
Nov 8 at 10:22












@Benoit QMyModel is the autogenerated class of MyModel @Entity class
– pvpkiran
Nov 8 at 11:06




@Benoit QMyModel is the autogenerated class of MyModel @Entity class
– pvpkiran
Nov 8 at 11:06




1




1




You could possibly look at some kind of reflection based solution. Iterate the fields of the filter and return the corresponding boolean condition. You could use a custom annotation on the fields to allow for more flexible binding.
– Alan Hay
Nov 8 at 12:09






You could possibly look at some kind of reflection based solution. Iterate the fields of the filter and return the corresponding boolean condition. You could use a custom annotation on the fields to allow for more flexible binding.
– Alan Hay
Nov 8 at 12:09














1 Answer
1






active

oldest

votes

















up vote
2
down vote



accepted










You can use lambda's, or (even better in this case) method reference:



public List<MyModel> findByFilter(FilterObject filterObject) {
BooleanBuilder builder = new BooleanBuilder();

QMyModel mymodel = QMyModel.myModel;

add(builder, filterObject.getName(), mymodel.name::contains);
add(builder, filterObject.getStatus(), mymodel.status::in);

...
}

private <T> void add(BooleanBuilder builder, T filterElement, Function<T, BooleanExpression> booleanExpressionFunction) {
if (valid(filterElement)) {
builder.and(booleanExpressionFunction.apply(filterElement));
}
}

private boolean valid(Object filterElement) {
if (filterElement == null) {
return false;
}
if (filterElement instanceof Collection) {
return !((Collection) filterElement).isEmpty();
}
return true;
}





share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53204767%2fquerydsl-avoiding-multiple-if-blocks%23new-answer', 'question_page');
    }
    );

    Post as a guest
































    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    down vote



    accepted










    You can use lambda's, or (even better in this case) method reference:



    public List<MyModel> findByFilter(FilterObject filterObject) {
    BooleanBuilder builder = new BooleanBuilder();

    QMyModel mymodel = QMyModel.myModel;

    add(builder, filterObject.getName(), mymodel.name::contains);
    add(builder, filterObject.getStatus(), mymodel.status::in);

    ...
    }

    private <T> void add(BooleanBuilder builder, T filterElement, Function<T, BooleanExpression> booleanExpressionFunction) {
    if (valid(filterElement)) {
    builder.and(booleanExpressionFunction.apply(filterElement));
    }
    }

    private boolean valid(Object filterElement) {
    if (filterElement == null) {
    return false;
    }
    if (filterElement instanceof Collection) {
    return !((Collection) filterElement).isEmpty();
    }
    return true;
    }





    share|improve this answer

























      up vote
      2
      down vote



      accepted










      You can use lambda's, or (even better in this case) method reference:



      public List<MyModel> findByFilter(FilterObject filterObject) {
      BooleanBuilder builder = new BooleanBuilder();

      QMyModel mymodel = QMyModel.myModel;

      add(builder, filterObject.getName(), mymodel.name::contains);
      add(builder, filterObject.getStatus(), mymodel.status::in);

      ...
      }

      private <T> void add(BooleanBuilder builder, T filterElement, Function<T, BooleanExpression> booleanExpressionFunction) {
      if (valid(filterElement)) {
      builder.and(booleanExpressionFunction.apply(filterElement));
      }
      }

      private boolean valid(Object filterElement) {
      if (filterElement == null) {
      return false;
      }
      if (filterElement instanceof Collection) {
      return !((Collection) filterElement).isEmpty();
      }
      return true;
      }





      share|improve this answer























        up vote
        2
        down vote



        accepted







        up vote
        2
        down vote



        accepted






        You can use lambda's, or (even better in this case) method reference:



        public List<MyModel> findByFilter(FilterObject filterObject) {
        BooleanBuilder builder = new BooleanBuilder();

        QMyModel mymodel = QMyModel.myModel;

        add(builder, filterObject.getName(), mymodel.name::contains);
        add(builder, filterObject.getStatus(), mymodel.status::in);

        ...
        }

        private <T> void add(BooleanBuilder builder, T filterElement, Function<T, BooleanExpression> booleanExpressionFunction) {
        if (valid(filterElement)) {
        builder.and(booleanExpressionFunction.apply(filterElement));
        }
        }

        private boolean valid(Object filterElement) {
        if (filterElement == null) {
        return false;
        }
        if (filterElement instanceof Collection) {
        return !((Collection) filterElement).isEmpty();
        }
        return true;
        }





        share|improve this answer












        You can use lambda's, or (even better in this case) method reference:



        public List<MyModel> findByFilter(FilterObject filterObject) {
        BooleanBuilder builder = new BooleanBuilder();

        QMyModel mymodel = QMyModel.myModel;

        add(builder, filterObject.getName(), mymodel.name::contains);
        add(builder, filterObject.getStatus(), mymodel.status::in);

        ...
        }

        private <T> void add(BooleanBuilder builder, T filterElement, Function<T, BooleanExpression> booleanExpressionFunction) {
        if (valid(filterElement)) {
        builder.and(booleanExpressionFunction.apply(filterElement));
        }
        }

        private boolean valid(Object filterElement) {
        if (filterElement == null) {
        return false;
        }
        if (filterElement instanceof Collection) {
        return !((Collection) filterElement).isEmpty();
        }
        return true;
        }






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 8 at 12:06









        Benoit

        1,8031822




        1,8031822






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53204767%2fquerydsl-avoiding-multiple-if-blocks%23new-answer', 'question_page');
            }
            );

            Post as a guest




















































































            Popular posts from this blog

            Landwehr

            Reims

            Schenkenzell