From e2c3cfd5b480da2f60ec2d0f24536c70f3347f7c Mon Sep 17 00:00:00 2001 From: matevip Date: Wed, 15 Jul 2026 14:26:47 +0800 Subject: [PATCH] fix(db): application-assigned ids for entities lacking auto-increment on PostgreSQL-compatible dialects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eight entities (fact, fact contradiction, morning-card seen, wiki hot cache / relation / transformation / transformation run / image caption cache) declared IdType.AUTO while their PostgreSQL-compatible migrations define the primary key as a plain BIGINT with no identity default. MyBatis-Plus omits the id column from the generated INSERT under AUTO, so every insert fails with a NOT NULL violation on those databases — silently on paths that only log a warning. Switch them to snowflake ASSIGN_ID, which works on all dialects since auto-increment columns accept explicit values. Add a parameterized contract test pinning the id strategy for all eight entities. --- .../fact/model/FactContradictionEntity.java | 2 +- .../mate/memory/fact/model/FactEntity.java | 2 +- .../memory/model/MorningCardSeenEntity.java | 2 +- .../mate/wiki/model/WikiHotCacheEntity.java | 2 +- .../model/WikiImageCaptionCacheEntity.java | 2 +- .../mate/wiki/model/WikiRelationEntity.java | 2 +- .../wiki/model/WikiTransformationEntity.java | 2 +- .../model/WikiTransformationRunEntity.java | 2 +- .../AutoIncrementFreePrimaryKeyTest.java | 49 +++++++++++++++++++ 9 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 mateclaw-server/src/test/java/vip/mate/architecture/AutoIncrementFreePrimaryKeyTest.java diff --git a/mateclaw-server/src/main/java/vip/mate/memory/fact/model/FactContradictionEntity.java b/mateclaw-server/src/main/java/vip/mate/memory/fact/model/FactContradictionEntity.java index b2e8b6c0..0a12ee29 100644 --- a/mateclaw-server/src/main/java/vip/mate/memory/fact/model/FactContradictionEntity.java +++ b/mateclaw-server/src/main/java/vip/mate/memory/fact/model/FactContradictionEntity.java @@ -14,7 +14,7 @@ import java.time.LocalDateTime; @TableName("mate_fact_contradiction") public class FactContradictionEntity { - @TableId(type = IdType.AUTO) + @TableId(type = IdType.ASSIGN_ID) private Long id; private Long agentId; diff --git a/mateclaw-server/src/main/java/vip/mate/memory/fact/model/FactEntity.java b/mateclaw-server/src/main/java/vip/mate/memory/fact/model/FactEntity.java index 0fb38a1e..6ed22308 100644 --- a/mateclaw-server/src/main/java/vip/mate/memory/fact/model/FactEntity.java +++ b/mateclaw-server/src/main/java/vip/mate/memory/fact/model/FactEntity.java @@ -17,7 +17,7 @@ import java.time.LocalDateTime; @TableName("mate_fact") public class FactEntity { - @TableId(type = IdType.AUTO) + @TableId(type = IdType.ASSIGN_ID) private Long id; private Long agentId; diff --git a/mateclaw-server/src/main/java/vip/mate/memory/model/MorningCardSeenEntity.java b/mateclaw-server/src/main/java/vip/mate/memory/model/MorningCardSeenEntity.java index df388dfe..62ad1c24 100644 --- a/mateclaw-server/src/main/java/vip/mate/memory/model/MorningCardSeenEntity.java +++ b/mateclaw-server/src/main/java/vip/mate/memory/model/MorningCardSeenEntity.java @@ -14,7 +14,7 @@ import java.time.LocalDateTime; @TableName("mate_morning_card_seen") public class MorningCardSeenEntity { - @TableId(type = IdType.AUTO) + @TableId(type = IdType.ASSIGN_ID) private Long id; private Long userId; diff --git a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiHotCacheEntity.java b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiHotCacheEntity.java index d3ff6b3a..73f9d617 100644 --- a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiHotCacheEntity.java +++ b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiHotCacheEntity.java @@ -21,7 +21,7 @@ import java.time.LocalDateTime; @TableName("mate_wiki_hot_cache") public class WikiHotCacheEntity { - @TableId(type = IdType.AUTO) + @TableId(type = IdType.ASSIGN_ID) private Long id; private Long kbId; diff --git a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiImageCaptionCacheEntity.java b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiImageCaptionCacheEntity.java index 02a4ebc8..d3126d8f 100644 --- a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiImageCaptionCacheEntity.java +++ b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiImageCaptionCacheEntity.java @@ -23,7 +23,7 @@ import java.time.LocalDateTime; @TableName("mate_wiki_image_caption_cache") public class WikiImageCaptionCacheEntity { - @TableId(type = IdType.AUTO) + @TableId(type = IdType.ASSIGN_ID) private Long id; /** SHA-256 hex digest (64 chars, lowercase) of the original image bytes. */ diff --git a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiRelationEntity.java b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiRelationEntity.java index 59d98310..1e0b7597 100644 --- a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiRelationEntity.java +++ b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiRelationEntity.java @@ -29,7 +29,7 @@ import java.time.LocalDateTime; @TableName("mate_wiki_relation") public class WikiRelationEntity { - @TableId(type = IdType.AUTO) + @TableId(type = IdType.ASSIGN_ID) private Long id; private Long kbId; diff --git a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiTransformationEntity.java b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiTransformationEntity.java index 75a35914..ebb7af21 100644 --- a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiTransformationEntity.java +++ b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiTransformationEntity.java @@ -22,7 +22,7 @@ import java.time.LocalDateTime; @TableName("mate_wiki_transformation") public class WikiTransformationEntity { - @TableId(type = IdType.AUTO) + @TableId(type = IdType.ASSIGN_ID) private Long id; /** diff --git a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiTransformationRunEntity.java b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiTransformationRunEntity.java index 2f7dc63b..d3401ec8 100644 --- a/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiTransformationRunEntity.java +++ b/mateclaw-server/src/main/java/vip/mate/wiki/model/WikiTransformationRunEntity.java @@ -19,7 +19,7 @@ import java.time.LocalDateTime; @TableName("mate_wiki_transformation_run") public class WikiTransformationRunEntity { - @TableId(type = IdType.AUTO) + @TableId(type = IdType.ASSIGN_ID) private Long id; private Long transformationId; diff --git a/mateclaw-server/src/test/java/vip/mate/architecture/AutoIncrementFreePrimaryKeyTest.java b/mateclaw-server/src/test/java/vip/mate/architecture/AutoIncrementFreePrimaryKeyTest.java new file mode 100644 index 00000000..8947685b --- /dev/null +++ b/mateclaw-server/src/test/java/vip/mate/architecture/AutoIncrementFreePrimaryKeyTest.java @@ -0,0 +1,49 @@ +package vip.mate.architecture; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import vip.mate.memory.fact.model.FactContradictionEntity; +import vip.mate.memory.fact.model.FactEntity; +import vip.mate.memory.model.MorningCardSeenEntity; +import vip.mate.wiki.model.WikiHotCacheEntity; +import vip.mate.wiki.model.WikiImageCaptionCacheEntity; +import vip.mate.wiki.model.WikiRelationEntity; +import vip.mate.wiki.model.WikiTransformationEntity; +import vip.mate.wiki.model.WikiTransformationRunEntity; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * Contract test: these entities are backed by tables whose PostgreSQL-compatible + * dialect defines the primary key as a plain BIGINT without an identity/sequence + * default. {@code IdType.AUTO} makes MyBatis-Plus omit the id column from the + * generated INSERT and rely on database-generated keys, which violates the + * NOT NULL constraint on those databases. Application-assigned snowflake ids + * ({@code IdType.ASSIGN_ID}) work across every supported dialect, since + * auto-increment columns also accept explicit values. + */ +class AutoIncrementFreePrimaryKeyTest { + + @ParameterizedTest + @ValueSource(classes = { + FactEntity.class, + FactContradictionEntity.class, + MorningCardSeenEntity.class, + WikiHotCacheEntity.class, + WikiRelationEntity.class, + WikiTransformationEntity.class, + WikiTransformationRunEntity.class, + WikiImageCaptionCacheEntity.class + }) + void primaryKeyUsesApplicationAssignedId(Class entityClass) throws NoSuchFieldException { + TableId tableId = entityClass.getDeclaredField("id").getAnnotation(TableId.class); + + assertNotNull(tableId, entityClass.getSimpleName() + ".id must be annotated with @TableId"); + assertEquals(IdType.ASSIGN_ID, tableId.type(), + entityClass.getSimpleName() + " must use application-assigned ids: its primary key" + + " column has no auto-increment default on PostgreSQL-compatible databases"); + } +}