Подтвердить что ты не робот

Jdbi возвращает автогенерированное значение для вставок

Я играю с dropwizard, и я хочу создать приложение REST, которое имеет различные отношения внешнего ключа в объектах.

Например, следующие 3 таблицы:

-- table persons
CREATE TABLE PUBLIC.PERSONS(
    ID BIGINT DEFAULT NOT NULL AUTOINCREMENT,
    FIRST_NAME VARCHAR(255),
    LAST_NAME VARCHAR(255),
    BIRTHDAY DATE,
    ADDRESS_ID BIGINT NOT NULL,
    CREATED TIMESTAMP DEFAULT 'current_timestamp',
    MODIFIED TIMESTAMP
);
ALTER TABLE PUBLIC.PERSONS ADD CONSTRAINT PUBLIC.PK_PERSONS PRIMARY KEY(ID);

-- table customers
CREATE TABLE PUBLIC.CUSTOMERS(
    ID BIGINT DEFAULT NOT NULL AUTOINCREMENT,
    PERSON_ID BIGINT NOT NULL,
    STATUS_CODE VARCHAR(100) DEFAULT 'ACQUISITION' NOT NULL,
    CREATED TIMESTAMP DEFAULT 'current_timestamp',
    MODIFIED TIMESTAMP
);
ALTER TABLE PUBLIC.CUSTOMERS ADD CONSTRAINT PUBLIC.PK_CUSTOMERS PRIMARY KEY(ID);

-- table addresses
CREATE TABLE PUBLIC.ADDRESSES(
    ID BIGINT DEFAULT NOT NULL AUTOINCREMENT,
    LINE_1 VARCHAR(255),
    LINE_2 VARCHAR(255),
    ZIP VARCHAR(255),
    CITY VARCHAR(255),
    COUNTRY_CODE VARCHAR(3),
    PHONE VARCHAR(255),
    FAX VARCHAR(255),
    CREATED TIMESTAMP DEFAULT 'current_timestamp',
    MODIFIED TIMESTAMP
);
ALTER TABLE PUBLIC.ADDRESSES ADD CONSTRAINT PUBLIC.PK_ADDRESSES PRIMARY KEY(ID);

-- and following forign key constraints:
ALTER TABLE PUBLIC.PERSONS ADD CONSTRAINT 
    PUBLIC.FK_PERSON_ADDRESS FOREIGN KEY(ADDRESS_ID) 
    REFERENCES PUBLIC.ADDRESSES(ID) ON DELETE SET NULL NOCHECK;

ALTER TABLE PUBLIC.CUSTOMERS ADD CONSTRAINT 
    PUBLIC.FK_CUSTOMER_PERSON FOREIGN KEY(PERSON_ID) 
    REFERENCES PUBLIC.PERSONS(ID) ON DELETE SET NULL NOCHECK;

Я начал внедрять customerDAO, который считывает данные таблицы клиентов и таблицы, на которые ссылаются, с одним SQL-запросом, который был не очень сложным:

@RegisterMapper(CustomerResultMapper.class)
public interface CustomerDAO {

    @SqlQuery("select p.id as person_id, "
            + "p.first_name, p.last_name, p.birthday, "
            + "c.id as customer_id, c.status_code, "
            + "a.id as address_id, a.line_1, a.line_2, a.zip, "
            + "a.city, a.country_code, a.phone, a.fax "
            + "from customers c, persons p, addresses a "
            + "where c.id = :id "
            + "and c.person_id = p.id "
            + "and p.address_id = a.id")
    public Customer findCustomerById(@Bind("id") long id);
}

(Для краткости я пропускаю картограф, так как это не мой вопрос)

Теперь я хочу вставить нового клиента, у меня есть все необходимые данные, включая данные, которые относятся к ссылочным таблицам.

Я не мог найти способ выполнения нескольких запросов с аннотациями jdbi, поэтому я решил, что мне нужно создать метод DAO для каждой из таблиц и вставить данные из java, вручную обновив ссылки на внешние ключи.

Но также это не работает, потому что я не смог найти способ прочитать значение автогенерированного идентификатора после вставки.

Любая идея, как я мог бы подходить к этой проблеме, чтобы я мог правильно поддерживать ссылки?

4b9b3361

Ответ 1

Ничего, я нашел решение тем временем, по крайней мере, как получить автоматически сгенерированный ключ:

в вашем DAO, добавьте аннотацию @GetGeneratedKeys, убедитесь, что ваше возвращаемое значение метода соответствует значению сгенерированного ключа:

@SqlUpdate("insert into addresses (line_1) values ('address line 1')")
@GetGeneratedKeys
public long insertAddress();

В вашем ресурсе вы можете просто использовать возвращаемое значение:

long id = customerDAO.insertAddress();
System.out.println("Found id " + id);

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

Если у кого-то есть идея, как я мог бы упростить этот процесс и позволить заполнению ссылок автоматически, мне все равно будет интересно узнать о нем.

Спасибо.

Ответ 2

В postgres вы можете получить не только один, но даже все автогенерируемые значения.

Вы можете сделать это, изменив @SqlUpdate на @SqlQuery и используя INSERT... RETURNING *, предположив, что у вас есть сопоставление для адреса:

@SqlQuery("insert into addresses (line_1) values ('address line 1') returning *")
public Address insertAddress(@BindBean Address address);