@Override
 public List<MovieImpl> getMovies(int firstResult, int maxResults, Map<String, String> sorts) {
   // From Query
   CriteriaQuery<MovieImpl> fromQuery = this.builder.createQuery(MovieImpl.class);
   Root<MovieImpl> movies = fromQuery.from(MovieImpl.class);
   // Select Query
   CriteriaQuery<MovieImpl> selectQuery = fromQuery.select(movies);
   // Order
   if (sorts != null) {
     List<Order> orders = new ArrayList<>();
     for (Map.Entry<String, String> entry : sorts.entrySet()) {
       String field = entry.getKey();
       String sortType = entry.getValue();
       if (field != null && sortType != null) {
         if (field.startsWith("file.")) {
           if (sortType.equalsIgnoreCase("asc")) {
             orders.add(builder.asc(movies.join("files", JoinType.LEFT).get(field.substring(5))));
           } else if (sortType.equalsIgnoreCase("desc")) {
             orders.add(builder.desc(movies.join("files", JoinType.LEFT).get(field.substring(5))));
           }
         } else if (field.startsWith("info.")) {
           if (sortType.equalsIgnoreCase("asc")) {
             orders.add(
                 this.builder.asc(
                     movies.join("information", JoinType.LEFT).get(field.substring(5))));
           } else if (sortType.equalsIgnoreCase("desc")) {
             orders.add(
                 this.builder.desc(
                     movies.join("information", JoinType.LEFT).get(field.substring(5))));
           }
         }
       }
     }
     selectQuery.orderBy(orders);
   }
   // Final Query
   TypedQuery<MovieImpl> typedQuery = this.entityManager.createQuery(selectQuery);
   // First Result
   if (firstResult >= 0) {
     typedQuery.setFirstResult(firstResult);
   }
   // Max Results
   if (maxResults >= 0) {
     typedQuery.setMaxResults(maxResults);
   }
   return typedQuery.getResultList();
 }
 @Override
 public List<? extends Movie> getMoviesByName(
     String movieName, int firstResult, int maxResults, Map<String, String> sorts) {
   // From Query
   CriteriaQuery<MovieImpl> fromQuery = this.builder.createQuery(MovieImpl.class);
   Root<MovieImpl> movies = fromQuery.from(MovieImpl.class);
   Path<String> infoMovieNameFiled = movies.join("information").get("name");
   Path<String> fileMovieNameFiled = movies.join("files").get("movieName");
   // Select Query
   CriteriaQuery<MovieImpl> selectQuery = fromQuery.select(movies);
   // Where Query
   selectQuery.where(
       this.builder.or(
           this.builder.like(
               this.builder.lower(infoMovieNameFiled), "%" + movieName.toLowerCase() + "%"),
           this.builder.like(
               this.builder.lower(fileMovieNameFiled), "%" + movieName.toLowerCase() + "%")));
   // Order
   if (sorts != null) {
     List<Order> orders = new ArrayList<>();
     for (Map.Entry<String, String> entry : sorts.entrySet()) {
       String field = entry.getKey();
       String sortType = entry.getValue();
       if (field != null && sortType != null) {
         if (field.startsWith("file.")) {
           if (sortType.equalsIgnoreCase("asc")) {
             orders.add(this.builder.asc(movies.join("files").get(field.substring(5))));
           } else if (sortType.equalsIgnoreCase("desc")) {
             orders.add(this.builder.desc(movies.join("files").get(field.substring(5))));
           }
         } else if (field.startsWith("info.")) {
           if (sortType.equalsIgnoreCase("asc")) {
             orders.add(this.builder.asc(movies.join("information").get(field.substring(5))));
           } else if (sortType.equalsIgnoreCase("desc")) {
             orders.add(this.builder.desc(movies.join("information").get(field.substring(5))));
           }
         }
       }
     }
     selectQuery.orderBy(orders);
   }
   // Final Query
   TypedQuery<MovieImpl> typedQuery = this.entityManager.createQuery(selectQuery);
   // First Result
   if (firstResult >= 0) {
     typedQuery = typedQuery.setFirstResult(firstResult);
   }
   // Max Results
   if (maxResults >= 0) {
     typedQuery = typedQuery.setMaxResults(maxResults);
   }
   return typedQuery.getResultList();
 }
 @Override
 public List<String> getImageAlbums(int firstResult, int maxResults, Map<String, String> sorts) {
   // From Query
   CriteriaQuery<String> fromQuery = this.builder.createQuery(String.class);
   Root<ImageImpl> images = fromQuery.from(ImageImpl.class);
   // Select Query
   CriteriaQuery<String> selectQuery = fromQuery.multiselect(images.get("album"));
   selectQuery.distinct(true);
   if (sorts != null) {
     List<Order> orders = new ArrayList<>();
     for (Map.Entry<String, String> entry : sorts.entrySet()) {
       String field = entry.getKey();
       String sortType = entry.getValue();
       if (field != null && sortType != null) {
         if (field.equals("album")) {
           if (sortType.equalsIgnoreCase("asc")) {
             orders.add(this.builder.asc(images.get(field)));
           } else if (sortType.equalsIgnoreCase("desc")) {
             orders.add(this.builder.asc(images.get(field)));
           }
         }
       }
     }
     selectQuery.orderBy(orders);
   }
   // Final Query
   TypedQuery<String> typedQuery = this.entityManager.createQuery(selectQuery);
   // First Result
   if (firstResult >= 0) {
     typedQuery = typedQuery.setFirstResult(firstResult);
   }
   // Max Results
   if (maxResults >= 0) {
     typedQuery = typedQuery.setMaxResults(maxResults);
   }
   return typedQuery.getResultList();
 }
  @Override
  public List<? extends Image> getImagesByField(
      String fieldName,
      String fieldValue,
      boolean strict,
      int firstResult,
      int maxResults,
      Map<String, String> sorts) {
    // From Query
    CriteriaQuery<ImageImpl> fromQuery = this.builder.createQuery(ImageImpl.class);
    Root<ImageImpl> images = fromQuery.from(ImageImpl.class);
    Path<String> name;
    if (fieldName.startsWith("file.")) {
      name = images.join("originalFile").get(fieldName.substring(5));
    } else {
      name = images.get(fieldName);
    }

    // Select Query
    CriteriaQuery<ImageImpl> selectQuery = fromQuery.select(images);
    // Where Query
    if (strict) {
      selectQuery.where(this.builder.like(this.builder.lower(name), fieldValue.toLowerCase()));
    } else {
      selectQuery.where(
          this.builder.like(this.builder.lower(name), "%" + fieldValue.toLowerCase() + "%"));
    }
    // Order query
    if (sorts != null) {
      List<Order> orders = new ArrayList<>();
      for (Map.Entry<String, String> entry : sorts.entrySet()) {
        String field = entry.getKey();
        String sortType = entry.getValue();
        if (field != null && sortType != null) {
          if (field.startsWith("file.")) {
            if (sortType.equalsIgnoreCase("asc")) {
              orders.add(this.builder.asc(images.join("originalFile").get(field.substring(5))));
            } else if (sortType.equalsIgnoreCase("desc")) {
              orders.add(this.builder.desc(images.join("originalFile").get(field.substring(5))));
            }
          } else {
            if (sortType.equalsIgnoreCase("asc")) {
              orders.add(this.builder.asc(images.get(field)));
            } else if (sortType.equalsIgnoreCase("desc")) {
              orders.add(this.builder.asc(images.get(field)));
            }
          }
        }
      }
      selectQuery.orderBy(orders);
    }
    // Final Query
    TypedQuery<ImageImpl> typedQuery = this.entityManager.createQuery(selectQuery);
    // First Result
    if (firstResult >= 0) {
      typedQuery = typedQuery.setFirstResult(firstResult);
    }
    // Max Results
    if (maxResults >= 0) {
      typedQuery = typedQuery.setMaxResults(maxResults);
    }
    return typedQuery.getResultList();
  }