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

            How to pass form data using jquery Ajax to insert data in database?

            National Museum of Racing and Hall of Fame

            Guess what letter conforming each word