Как бы я использовал java.util.Collections для имитации операции SQL INNER JOIN? - PullRequest
0 голосов
/ 03 декабря 2018

Как бы я использовал Java Collections для имитации операции SQL INNER JOIN?


В базе данных у меня есть:

TABLE Person

KEY  NAME
11   Senor
other non-important entries...

TABLE Thing

KEY  ITEM
AA   Moustache
BB   Sombrero
CC   HotSauce
other non-important entries...

TABLE PersonToThing

PERSON_KEY  THING_KEY  HAS
11          AA         Y
11          BB         N
11          CC         Y
other non-important entries...

Я хочу эмулировать оператор SQL:

SELECT Person.NAME, Thing.ITEM, PersonToThing.HAS 
FROM Person 
INNER JOIN PersonToThing ON Person.KEY=PersonToThing.PERSON_PKEY
INNER JOIN Thing ON Thing.KEY=PersonToThing.THING_KEY
WHERE Person.NAME="Senor";

, который дает набор результатов:

NAME   ITEM       HAS
Senor  Moustache  Y
Senor  Sombrero   N
Senor  HotSauce   Y

Я хочу поместить каждую таблицу в карту Java.

Я экспортировал таблицы в операторы INSERT TABLE.

Я буду заполнять Карты, просматривая операторы INSERT TABLE.

Запуск системы моделирования реляционных баз данных, к сожалению, просто невозможен.


Что яНе понимаю, как мне организовать Коллекции или Карты и как связать их вместе, чтобы имитировать операцию ВНУТРЕННЕГО СОЕДИНЕНИЯ?


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

Ответы [ 3 ]

0 голосов
/ 03 декабря 2018

В теории множеств внутреннее соединение по сути является операцией пересечения .В коллекции Java не встроены те же функции теории множеств, но в них есть похожие функции для объединения (addAll) и пересечения (retainAll).См. этот вопрос для получения дополнительной информации о том, как внутреннее соединение / пересечение может быть реализовано с помощью Set или других коллекций.

Основная проблема здесь с использованием теории множеств - это наличие трех различных типов объектов, ни один из которых не наследует друг друга, чего можно ожидать в правильной модели отношений.Например, было бы намного проще, если бы Person и Thing унаследовали от PersonToThing как родительский класс:

class Person extends PersonToThing {
    // ...
}

class Thing extends PersonToThing {
    // ...
}

class PersonToThing {
    // now Person_Key and Thing_Key can be inherited
    String personKey;
    String thingKey;
    // etc...
}

Используя эту модель, мы можем теперь иметь коллекцию объектов PersonToThing и правильно проиллюстрировать как одно-мани-отношения:

Set<PersonToThing> people = selectAllFrom("Person");
Set<PersonToThing> thing = selectAllFrom("Thing");
Set<PersonToThing> innerJoin = people;
people.addAll(thing);
innerJoin.retainAll(thing);

Если вы переопределите функцию equals() объекта для проверки своего ключа, вы можете выполнить объединение по своему усмотрению, включая фильтр имени сеньора или добавление вспомогательной функции для его создания.более удобный для повторного использования дизайн:

@Override
public boolean equals(Object personToThing) {
    if (personToThing.getPersonKey() != null) {
        return personKey.equals(personToThing.getPersonKey());
    else
        return thingKey.equals(personToThing.getThingKey());
}

Это сделано потому, что Set использует equals(), чтобы проверить, являются ли два объекта одинаковыми.Таким образом, когда это происходит, мы сравниваем ключи так, как это делает соединение.

Я оставил детали функции selectAllFrom () абстрактными, поскольку вы не предоставили никакого конкретного шаблонного кода базы данных,но это должно быть довольно просто реализовать, как вам нужно.

0 голосов
/ 03 декабря 2018

Ну, это кажется не простым, но это возможно.
Сначала некоторая подготовка - я использую Project Lombok , чтобы генерировать геттеры / сеттеры и конструкторы, используя простые аннотации, просто создайте Mavenспроектируйте и добавьте в него эту зависимость:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.4</version>
    <scope>provided</scope>
</dependency>

Ниже приведены определения наших классов и таблиц с данными:

@AllArgsConstructor @Getter
public static class Person {
    private String key, name;
}

@AllArgsConstructor @Getter
public static class Thing {
    private String key, item;
}

@AllArgsConstructor @Getter
public static class PersonToThing {
    private String personKey, thingKey, has;
}

static Collection<Person> tablePerson = Arrays.asList(
        new Person("11", "Senor"),
        new Person("22", "Tom"));

static Collection<Thing> tableThing = Arrays.asList(
        new Thing("AA", "Moustache"),
        new Thing("BB", "Sombrero"),
        new Thing("CC", "HotSauce"),
        new Thing("XX", "Not important")
);

static Collection<PersonToThing> tablePerson2Thing = Arrays.asList(
        new PersonToThing("11", "AA","Y"),
        new PersonToThing("11", "BB","N"),
        new PersonToThing("11", "CC","Y"));

Теперь фрагмент кода, который выполняетобъединение этих трех коллекций.

@AllArgsConstructor(staticName = "of") @Getter
public static class Tuple<V1,V2>{
    private V1 v1;
    private V2 v2;
}

@AllArgsConstructor(staticName = "of") @Getter
public static class Triple<V1,V2,V3>{
    private V1 v1;
    private V2 v2;
    private V3 v3;
}

public static void main(String[] args) {
    tablePerson.stream()
            // WHERE Person.NAME="Senor";
            .filter(x->x.getName()=="Senor")
            // INNER JOIN PersonToThing
            .flatMap( p -> tablePerson2Thing.stream()
                    .map(p2t-> Tuple.of(p,p2t))
                    // ON Person.KEY=PersonToThing.PERSON_PKEY
                    .filter(t->t.getV1().getKey()==t.getV2().getPersonKey())
            )
            // INNER JOIN Thing
            .flatMap( p2t-> tableThing.stream()
                    .map(t-> Triple.of(p2t.getV1(),p2t.getV2(),t))
                    // ON Thing.KEY=PersonToThing.THING_KEY
                    .filter(t->t.getV2().getThingKey()==t.getV3().getKey())
            )
            // SELECT Person.NAME, Thing.ITEM, PersonToThing.HAS 
            .forEach(x->System.out.println(x.getV1().getName()+ " / " + x.getV3().getItem() + " /  " + x.getV2().getHas()));
}

и результат:

Senor / Moustache /  Y
Senor / Sombrero /  N
Senor / HotSauce /  Y
0 голосов
/ 03 декабря 2018

В вашем примере есть отношения один-ко-многим между людьми и вещами.Для меня сложнее думать об такого рода отношениях с точки зрения базы данных, чем с точки зрения Java / OOP.

В вашей БД - ваша таблица присоединения к таблице вещей для предоставления списка вещейу каждого человека есть.

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

Итак, в Java вы по сути спрашиваете, как смоделировать это:

public class Person() {    
   private List<Thing> things;
}

...

public class SomeClass() {
    private List<Person> peopleWithThings;
}  

IMO, вы можете сделать это двумя способами -

  1. Просто используйтепростые старые объекты Java в вашем домене, как я делал выше
  2. Используйте что-то вроде мультикарты Guava для создания карты строк (имен людей) в список вещей.

Использованиеmultimap, у вас будет что-то вроде:

String key = "Senor";
Multimap<String, Thing> map = ArrayListMultimap.create();

map.put(key, thing1);
map.put(key, thing2);

assertEquals(2, map.size());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...