最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - JPA InheritanceType.JOINED complete partially popolated tables - Stack Overflow

programmeradmin2浏览0评论

Consider the following simple hierarchy:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Setter
@Getter
public class Brand {
    @Id
    Long id;
    String name;
}

@Entity
@Setter
@Getter
public class BrandDetail extends Brand {
    private String wpCode;
}

Suppose we have a row in brand table with id 1L and no corresponding brand_detail row.

The following:

@Service
public class BrandService {
    @Autowired
    private BrandRepository brandRepository;

    @Autowired
    private BrandDetailRepository brandDetailRepository;

    public void addBrandDetails(Long brandId, String wpCode) {
        // Fetch the existing Brand entity
        Brand brand = brandRepository.findById(brandId).orElseThrow(() -> new EntityNotFoundException("Brand not found"));

        // Create a BrandDetail entity
        BrandDetail brandDetail = new BrandDetail();
        brandDetail.setId(brand.getId()); // Set the same ID as the existing Brand
        brandDetail.setName(brand.getName()); // Copy the existing fields
        brandDetail.setWpCode(wpCode); // Set the new detail

        // Save the BrandDetail entity
        brandDetailRepository.save(brandDetail);
    }
}

fails with:

Hibernate: select b1_0.id,case when b1_1.id is not null then 1 when b1_0.id is not null then 0 end,b1_0.name,b1_1.wp_code from brand b1_0 left join brand_detail b1_1 on b1_0.id=b1_1.id where b1_0.id=?
2025-01-30T16:23:23.680+01:00 TRACE 219372 --- [demo] [           main] .hibernate.orm.jdbc.bind              : binding parameter (1:BIGINT) <- [1]
Hibernate: insert into brand (name,id) values (?,?)
2025-01-30T16:23:23.704+01:00 TRACE 219372 --- [demo] [           main] .hibernate.orm.jdbc.bind              : binding parameter (1:VARCHAR) <- [test]
2025-01-30T16:23:23.704+01:00 TRACE 219372 --- [demo] [           main] .hibernate.orm.jdbc.bind              : binding parameter (2:BIGINT) <- [1]
Hibernate: select b1_0.id,case when b1_1.id is not null then 1 when b1_0.id is not null then 0 end,b1_0.name,b1_1.wp_code from brand b1_0 left join brand_detail b1_1 on b1_0.id=b1_1.id where b1_0.id=?
2025-01-30T16:23:23.709+01:00 TRACE 219372 --- [demo] [           main] .hibernate.orm.jdbc.bind              : binding parameter (1:BIGINT) <- [1]
Hibernate: select bd1_0.id,bd1_1.name,bd1_0.wp_code from brand_detail bd1_0 join brand bd1_1 on bd1_0.id=bd1_1.id where bd1_0.id=?
2025-01-30T16:23:23.712+01:00 TRACE 219372 --- [demo] [           main] .hibernate.orm.jdbc.bind              : binding parameter (1:BIGINT) <- [1]
Hibernate: insert into brand (name,id) values (?,?)
2025-01-30T16:23:23.714+01:00 TRACE 219372 --- [demo] [           main] .hibernate.orm.jdbc.bind              : binding parameter (1:VARCHAR) <- [test]
2025-01-30T16:23:23.714+01:00 TRACE 219372 --- [demo] [           main] .hibernate.orm.jdbc.bind              : binding parameter (2:BIGINT) <- [1]
2025-01-30T16:23:23.715+01:00  WARN 219372 --- [demo] [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: -104, SQLState: 23505
2025-01-30T16:23:23.715+01:00 ERROR 219372 --- [demo] [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : integrity constraint violation: unique constraint or index violation ; SYS_PK_10092 table: BRAND

How can I add the details to an existing Brand ?

I've also tried to add to the BrandRepository the query

    @Query("select new com.example.demo.BrandDetail(b.id, b.name) from Brand b where id = :id")
    BrandDetail findByBrandId(Long id);

For the sake of completeness here is a simple test:

@SpringBootTest(properties = {
    "spring.datasource.url=jdbc:tc:mariadb:10:///test?TC_TMPFS=/testtmpfs:rw",
    "spring.jpa.hibernate.ddl-auto=update",
    "spring.jpa.show-sql=true",
    "logging.level.hibernate.orm.jdbc.bind=trace"
})
class BrandServiceTest {

    public static final long BRAND_WITH_DETAILS_ID = 2L;
    public static final long BRAND_WITH_NO_DETAILS_ID = 1L;

    @Autowired
    private BrandRepository brandRepository;

    @Autowired
    private BrandDetailRepository brandDetailRepository;

    @BeforeEach
    void setup() {
        Brand brand = new Brand();
        brand.setId(BRAND_WITH_NO_DETAILS_ID);
        brand.setName("test");
        brandRepository.saveAndFlush(brand);

        BrandDetail brandDetail = new BrandDetail();
        brandDetail.setId(BRAND_WITH_DETAILS_ID);
        brandDetail.setName("Test with details");
        brandDetail.setWpCode("WP2");
        brandDetailRepository.saveAndFlush(brandDetail);
    }

    @Test
    void addBrandDetails() {
        assertThat(brandRepository.count()).isEqualTo(2);
        assertThat(brandDetailRepository.count()).isEqualTo(1);
        assertThat(brandRepository.findById(BRAND_WITH_NO_DETAILS_ID).isPresent()).isTrue();
        assertThat(brandDetailRepository.findById(BRAND_WITH_NO_DETAILS_ID).isPresent()).isFalse();

        BrandDetail brandDetail = brandRepository.findByBrandId(BRAND_WITH_NO_DETAILS_ID);
        assertThat(brandDetail.getId()).isEqualTo(BRAND_WITH_NO_DETAILS_ID);
        brandDetail.setWpCode("WP1");
        brandDetailRepository.saveAndFlush(brandDetail);
        assertThat(brandRepository.count()).isEqualTo(2);
        assertThat(brandDetailRepository.count()).isEqualTo(2);
    }
}
发布评论

评论列表(0)

  1. 暂无评论