У меня есть следующая таблица (фрагмент):
create table users
(
user_id uniqueidentifier default newid() not null primary key,
name varchar(192),
...
)
и сущность:
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
@Table(value = "users")
public class User {
@Id
@Column("user_id")
private UUID userId;
}
Запуск сохранения в базе данных h2 с конфигурациями sql-сервера работает нормально, однако, если запустить сохранение в реальной базе данных sql-сервера, я получаю
java.lang.IllegalArgumentException: After saving the identifier must not be null!
at org.springframework.util.Assert.notNull(Assert.java:201)
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.store(JdbcAggregateTemplate.java:364)
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.save(JdbcAggregateTemplate.java:161)
Я видел различные другие сообщения, посвященные аналогичным проблемам, однако большинство из них используют подходы через спящий режим/JPA, чего я хочу избежать, если это возможно.
Я пробовал разные strategy настройки @GeneratedValue аннотации, но ни один из них не сработал.
Есть ли способ решить эту проблему исключительно с помощью spring-data-jdbc?
Как мне правильно аннотировать свойство id, чтобы sql-server создавал uuid и передал его в spring-data-jdbc?
Я использую SQL Server 2019 с настройками по умолчанию.
редактировать:
Чтобы сохранить объект, я использую save из UserRepository extends CrudRepository<User, UUID>
редактировать-2:
С помощью этого обходного пути я смог заставить его работать:
@Bean
BeforeConvertCallback<AlertUser> beforeConvertCallback() {
return (user) -> {
if (user.getId() == null) {
user.setId(UUID.randomUUID());
}
return user;
};
}
Но это все еще не желаемое решение, поскольку оно зависит от генерации uuid на стороне клиента.
Я копнул немного дальше и обнаружил, что проблема возникает, когда Spring пытается получить сгенерированные идентификаторы. Afaics ожидает ResultSet, содержащую строку со свойством GENERATED_KEYS, но на sql-сервере это свойство никогда или по-другому не устанавливается СУБД, как кажется.




Используйте аннотацию @GeneratedValue со стратегией GenerationTime.ALWAYS.
@Id
@GeneratedValue(strategy = GenerationTime.ALWAYS, jdbcType = JdbcType.UNIQUEIDENTIFIER)
@Column("user_id")
private UUID userId;
Не могли бы вы указать, какую версию javax.persistence вы используете? Не удалось найти недвижимость jdbcType или GenerationType.ALWAYS на @GeneratedValue,.. я на javax.persistence:javax.persistence-api:2.2
@GeneratedValue — это аннотация JPA. Это совершенно не связано с Spring Data JDBC и поэтому не повлияет на вашу настройку Spring Data JDBC.
Насколько я могу судить, Microsoft SqlServer (или его драйвер JDBC) не возвращает идентификаторы, сгенерированные так, как вы настраиваете свою таблицу. Поэтому Spring Data JDBC не может их подобрать.
Правильный способ обойти это - использовать конструкцию, которую вы уже обнаружили:
@Bean
BeforeConvertCallback<AlertUser> beforeConvertCallback() {
return (user) -> {
if (user.getId() == null) {
user.setId(UUID.randomUUID());
}
return user;
};
}
Вы, вероятно, захотите удалить предложение default newid() на стороне базы данных, чтобы не путать людей, где генерируется UUID.
Это "правильный" подход, потому что
Конечно, всегда есть сценарий, когда кто-то выше в пищевой цепочке сказал вам сгенерировать UUID в базе данных. В таком случае есть пара вариантов:
NamedParameterJdbcTemplate или JdbcTemplate, чтобы вставить свою сущность, и используйте подход, указанный выше, для получения сгенерированного идентификатора. Вы можете поместить этот код в реализацию пользовательского метода в вашем репозитории Spring Data JDBC.Я был немного обеспокоен тем, что генерация uuid на стороне клиента может привести к конфликту uuid, но, переосмыслив это, я предполагаю, что вероятность будет довольно низкой. На самом деле не требуется, чтобы я использовал генерацию uuid на стороне сервера, это было больше похоже на то, что у меня было ощущение, что это такой базовый сценарий, я не могу представить, что нет «весеннего» способа настроить/исправить это.
Можете ли вы показать, как вы сохраняете свою сущность?