Java Play Framework с использованием Find и JPQL для создания списка объектов с дубликатами из списка строк

Итак, я новичок в Java, и Play все еще время от времени путается в квазиобъектно-ориентированном программировании...

Мне нужно преобразовать строку с разделителями с повторяющимися значениями в список объектов, также с этими повторяющимися значениями, в том же порядке, что и строка.

Пример:

У меня есть форма, в которой пользователь отправляет строку с разделителями-пробелами. Например:

http://www.feedme.com?food=apple+orange+banana+apple+grape+apple

это идет к

public static List<Food> getFoodList(String foodString) {
    foodString = foodString.trim();
    List<String> foods = Arrays.asList(foodString.split("\\s+")); 
    List<Food> foodList = Food.find("name IN (:foods)").bind("foods", foods).fetch();
    return foodList;
}

Я вывожу цикл списка String на экран и получаю ожидаемое: яблоко, апельсин, банан, яблоко, виноград, яблоко.

Я печатаю значение Food.name для каждого в цикле foodList и получаю: Виноград Яблоко Банан Апельсин

Это явно проблема с IN в предложении WHERE, так как это ожидаемое поведение.

Итак, мое текущее решение состоит в том, чтобы вручную заполнить список, прокручивая список и выполняя следующие действия для каждой строки в списке продуктов.

List<Food> foodList = new ArrayList<Food>(foods.size());
    for ( String name: foods ){
        Food food = Food.find("byName", name).first();
        foodList.add(food);
    }

Это работает так, как я хочу, но просто не кажется очень элегантным или эффективным. Требуются дубликаты, поэтому я думаю, что это исключает IN. У кого-нибудь есть идеи получше? Если ответ отрицательный, то тоже буду признателен!

Большое спасибо.


person bladmiral    schedule 17.03.2012    source источник


Ответы (1)


Не существует (по крайней мере, разумного) способа построить такой JPQL-запрос. Если выполнение слишком большого количества запросов в цикле беспокоит, вы можете получить объекты Food в одном запросе и впоследствии сопоставить их с чем-то вроде (не скомпилировано/проверено, а просто как идея):

List<Food> matchFoodNamesToFoods(List<String> foodNames , List<Food> foodList ) {
    final ArrayList<Food> result = new ArrayList<Food>();
    for (String foodName: foodNames) {
        for (Food food: foodList) {
            if (food.getName().equals(foodName)) {
                result.add(food);
            }
            //maybe you want to add null here when no match
        }
    }
    return result;
}

В зависимости от размера foodList и ожидаемого количества дубликатов (и, возможно, вы также найдете его более понятным), вы также можете сначала создать карту с записями foodName/Food и запросить ее во внутреннем цикле:

List<Food> matchFoodNamesToFoods(List<String> foodNames , List<Food> foodList ) {
    final ArrayList<Food> result = new ArrayList<Food>();
    final Map<String, Food> foodNameToFood = new HashMap<String, Food>();
    for (Food food: foodList) {
        for (String foodName: foodNames) {
            if (food.getName().equals(foodName)) {
                foodNameToFood.put(foodName, food);
            }
        }
    }
    for (String foodName: foodNames) {
        result.add(foodNameToFood.get(foodName));
    }
    return result;
}

Кроме того, вы должны решить, приводит ли отсутствующая еда для какого-либо имени к нулевой записи в результате или это такая аномалия, что в таком случае вы предпочитаете исключение.

person Mikko Maunu    schedule 17.03.2012