Как обновить существующие записи в коллекции @OneToMany? - PullRequest
0 голосов
/ 19 января 2019

Я храню коллекцию бесплатных прокси в базе данных. Прокси-объект состоит из:

  • IP-адрес
  • Порт
  • Список источников

Источник - в основном веб-сайт, где я нашел эту информацию прокси. Вот моя схема:

таблица прокси:

+--------------+-------------+------+-----+---------+-------+
| Field        | Type        | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| id           | varchar(45) | NO   | PRI | NULL    |       |
| ip_address   | varchar(40) | NO   |     | NULL    |       |
| port         | smallint(6) | NO   |     | NULL    |       |
+--------------+-------------+------+-----+---------+-------+

Источник:

+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int(11)      | NO   | PRI | NULL    | auto_increment |
| resource | varchar(200) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+

proxy_sources, который объединяет первые две таблицы:

+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| proxy_id  | varchar(45) | NO   | MUL | NULL    |       |
| source_id | int(11)     | NO   | MUL | NULL    |       |
+-----------+-------------+------+-----+---------+-------+

Мои классы Java ORM:

@Entity
@Table(name = "proxy")
public class Proxy {

    @Id
    @Column(name = "id")
    private String id;

    @Column(name = "ip_address")
    private String ipAddress;

    @Column(name = "port")
    private int port;

    @OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
    @JoinTable(
            name = "proxy_sources",
            joinColumns = @JoinColumn(name = "proxy_id"),
            inverseJoinColumns = @JoinColumn(name = "source_id")
    )
    private List<Source> sources = new ArrayList<>();

    ...
}


@Entity
@Table(name = "source")
public class Source {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "resource")
    private String resource;

    ...
}

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

Прокси-объект имеет 2 источника:

  1. с ресурсом = "res1"
  2. с ресурсом = "res2"

Если исходная таблица уже содержит запись с source = "res1", я хочу заполнить ее свойство id в java-объекте из базы данных, чтобы избежать создания дубликата.

Сейчас я делаю это вручную в своем классе репозитория:

public String save(Proxy proxy) {
    populate(proxy.getSources());
    return (String) sessionFactory.getCurrentSession().save(proxy);
}

Вот метод заполнения:

private void populate(List<Source> sources) {
    if (sources.isEmpty()) {
        return;
    }

    List<String> resources = sources.stream().map(Source::getResource).collect(toList());

    List<Source> existing = sessionFactory.getCurrentSession()
            .createQuery("FROM Source source WHERE source.resource IN (:resources)", Source.class)
            .setParameterList("resources", resources)
            .list();

    sources.forEach(source -> existing.stream()
            .filter(s -> s.getResource().equals(source.getResource()))
            .findAny()
            .ifPresent(s -> source.setId(s.getId())));
}

По сути, я проверяю наличие каждого источника в коллекции источников. Если источник с таким же значением ресурса уже существует, я заполняю его идентификатор из базы данных. Непустой идентификатор избегает создания дубликатов.

Это работает, но, возможно, есть более чистое решение этой проблемы?

1 Ответ

0 голосов
/ 20 января 2019

Первое, что вы можете сделать, чтобы избежать дублирования, - это создать уникальный ключ в таблице source в столбце resource.Таким образом, даже если вы допустите ошибку в своем коде, база данных выдаст ошибку, если вы попытаетесь сохранить дубликат регистра.

С учетом вышесказанного, нет простого способа сохранить только те объекты, которые несуществуют в базе данных.Вы либо делаете столбец resource своим первичным ключом, а столбец id выбрасываете (что я не считаю хорошим выбором), либо вам нужно сделать выбор в базе данных.

Этот вопрос содержит более подробную информацию о втором параметре

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

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