Executando verificação de segurança...
3

Eu acho que entendi o que você quer fazer. Mas tenho uma dúvida: o seu modelo de negócio realmente precisa de herança? Se você deixar de lado o banco de dados e modelar o seu sistema com um diagrama de classes, você modelaria uma herança ou uma associação simples? Algo que pode te ajudar é fazer a seguinte pergunta: Existem múltiplas classes que podem estender ArticleModel, ou é apenas uma?

Estou fazendo a pergunta porque talvez existam outras soluções que não sejam a herança. Mas assumindo que herança é mesmo o que você precisa, então vai ter um probleminha que você vai ter que resolver com o modelo que você descreveu. Imagine que você tem a tabela TB_ARTICLE_MODEL e várias outras tabelas a "estendendo", como o banco de dados saberia qual a tabela de extensão para cada registro na tabela TB_ARTICLE_MODEL? A solução escolhida pelo time do JPA foi criar um atributo para fazer a distinção. Aqui fica um exemplo que eu fiz:

Note o atributo tb_article_model.proj_type vai ser usado para saber qual a tabela de extensão.

    create table tb_article_model (
        article_code uuid not null,
        proj_type varchar(31) not null,
        article_name varchar(255),
        primary key (article_code)
    )
    create table tb_products_in_stock (
        weigth float(53),
        article_code uuid not null,
        primary key (article_code)
    )
    alter table if exists tb_products_in_stock 
       add constraint FKdx5614f3luj74nb5m7nf4kd5s 
       foreign key (article_code) 
       references tb_article_model

O codigo fica assim:

@Entity
@Table(name = "TB_ARTICLE_MODEL")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="PROJ_TYPE")
public class ArticleModel {
    @Id
    private UUID articleCode;
    private String articleName;
}

@Entity
@Table(name = "TB_PRODUCTS_IN_STOCK")
@DiscriminatorValue("PRODUCT_MODEL")
public class ProductModel extends ArticleModel {
    private Double weigth;
}

@SpringBootTest
public class Heranca {
    @Autowired
    private ArticleRepository articleRepository;

    @Test
    void test() {
        var p = new ProductModel();
        p.setArticleCode(UUID.randomUUID());
        p.setArticleName("Meu nome");
        p.setWeigth(100d);
        articleRepository.save(p);
    }
}

O SQL de insercao ficaria assim:

Hibernate: 
    insert 
    into
        tb_article_model
        (article_name,proj_type,article_code) 
    values
        (?,'PRODUCT_MODEL',?)
Hibernate: 
    insert 
    into
        tb_products_in_stock
        (weigth,article_code) 
    values
        (?,?)

Espero ter ajudado.

Carregando publicação patrocinada...
2

Mas tenho uma dúvida: o seu modelo de negócio realmente precisa de herança?

Na verdade não, meu conhecimento ainda é bem limitado, por isso me pareceu o melhor caminho.
Tentei fazer agora por composição, apesar de fazer total sentido, não havia pensado nisso até lembrar que o Deschamps falou tocou no assunto em um dos vídeos que assiste a alguns meses. Lembrei do termo logo depois que te respondi e fui ler sobre o conceito.
Usei, deu um erro na hora de subir a aplicação:
Could not determine recommended JdbcType for Java type 'dev.tadeupinheiro.apistockinputspringboot.models.ArticleModel

Não sei significa alguma coisa sem ter as classes da aplicação para entender, mas enfim, mesmo que eu consiga resolver esse erro, não acho que seria performático, salvar todas as classes em cada registro que eu fizer no db.

Vamos lá, vou tentar explicar como funciona o negócio:

Existe os ARTIGOS, que seríam os "modelos" do produto. Exemplo: Existe o artigo chamado UNIPACIFIC, que é um tipo de tecido, que tem seus atributos (nome, peso, fabricante e composição), ele não vai ser alterado, vai ser cadastro e fica lá, eventualmente se cadastraria outros artigos, mas seria em outro métodos, essa parte seria "fácil".

Existe também as CORES, o artigo UNIPACIFIC tem sua paleta de cores, que serve para ele a para outros artigos também. Se encaixa no mesmo esquema: eventualmente se cadastria outros mas não é o centro da api no momento.

Por fim, existe o ROLO, que é o ponto central aqui.
O rolo possui o número(que seria o ID dele), possui tamanho, qualidade, tratamento, preço de custo e etc.
A questão é que o rolo não se repete e não seria extendido por nenhuma outra classe. Terá a entrada no banco de dados e na venda teria a saída e o id não se repete.
Mas o rolo também terá o artigo e seus atributos e a cor e seus atributos, exemplo:
Número do rolo: 156879 (primary key)
Tamanho: 100m
Preço de custo: 19,00
Artigo: Unipacific
Fabricante: Satanense
(demais atributos do artigo)
Código da cor: 5890
Cor: Azul

Então a minha intenção seria:

Salvar o rolo e seus atributos na tabela: TB_PRODUCTS_IN_STOCK, e nele ter a coluna de chave estrangeira fazendo referência para o artigo e a cor. Não salvando a classe completa dentro da tabela como seria na composição. Seria somente a referência e na hora de puxar o relatório puxar pela chave.

Caso faça diferença e possa dar uma olhada:

Repositório GITHUB:
https://github.com/tadeupinheiro/api-stock-input-spring-boot/tree/Using-composition/src/main/java/dev/tadeupinheiro/apistockinputspringboot

Está na branch: Using-Composition

2

Você encontrou o erro "Could not determine recommended JdbcType for Java type 'dev.tadeupinheiro.apistockinputspringboot.models.ArticleModel'" porque você colocou uma classe dentro da outra. Neste caso, o JPA pensa que você quer serializar a classe em uma coluna; contudo, o Jdbc não sabe como serializar a classe ArticleModel e falha. Mas não vamos nos preocupar com isso por agora porque não é o caminho que queremos.

Lendo a sua descrição, no meu entendimento, o seu modelo de negócio fica assim:

  • Cor:
    • Uma Cor pode estar associada a vários Artigos.
  • Rolo:
    • Um Rolo está associado a apenas um Artigo.
    • Um Rolo está associado a apenas um Produto.
  • Artigo:
    • Um Artigo está associado a apenas uma Cor.
    • Um Artigo está associado a vários Rolos.
  • Produto:
    • Um Produto está associado a vários Rolos.

Um diagrama bidirecional ficaria assim:

              +---------------+
              |    Artigo     |
              +---------------+
       UmParaMuitos  / \  MuitosParaUm                                                    
                    /   \ 
                   /     \
                  /       \
   MuitosParaUm  /         \ UmParaMuitos
+---------------+           ----------------+
|     Rolo      |           |     Cor       |
+---------------+           +---------------+
   MuitosParaUm |
                |
                |
   UmParaMuitos |
+---------------+
|    Produto    |
+---------------+ 

Relacionamentos bidirecionais são mais difíceis de trabalhar. Eu começaria com um diagrama unidirecional e depois mudaria para um bidirecional se houver necessidade. Fica difícil sugerir um modelo unidirecional sem saber a API do sistema, mas eu acho que você deve estar caminhando para algo assim:

              +---------------+
              |    Artigo     |
              +---------------+
                     / \  MuitosParaUm
                    /   \ 
                   /     \
                  /       \
   MuitosParaUm  /         \ 
+---------------+           ----------------+
|     Rolo      |           |     Cor       |
+---------------+           +---------------+
                |
                |
                |
   UmParaMuitos |
+---------------+
|    Produto    |
+---------------+ 

Com esse diagrama, o fluxo da API ficaria assim:

  1. Criar uma Cor.
  2. Criar um Artigo contendo sua respectiva Cor.
  3. Criar vários Rolos contendo seus respectivos Artigos.
  4. Criar um Produto contendo seus respectivos Rolos.

Neste tipo de organização, quando criamos um Produto, só precisamos dizer quais os rolos incluídos no Produto, e as informações sobre Artigo e Cor já estarão disponíveis em seus sub-objetos. A API de criar um Produto ficaria legal porque os clientes só precisam passar os IDs dos rolos para criar, e o backend saberia toda a informação.

O banco de dados ficaria assim. Note a join table entre Produtos e Rolos tb_products_in_stock_rolls:

    create table roll_model (
        article_article_code uuid, -- FK
        roll_number uuid not null, -- PK
        primary key (roll_number)
    )
    create table tb_article_model (
        article_code uuid not null, -- PK
        cor_color_code uuid,        -- FK
        primary key (article_code)
    )
    create table tb_color (
        color_code uuid not null,  -- PK
        color_name varchar(255),
        primary key (color_code)
    )
    create table tb_products_in_stock (
        cost_price float(53) not null,
        size float(53) not null,
        weigth float(53) not null,
        id uuid not null,            -- PK
        invoice_date varchar(255),
        invoice_number varchar(255),
        order_number varchar(255),
        treatment varchar(255),
        primary key (id)   
    )
    create table tb_products_in_stock_rolls (
        product_model_id uuid not null,                    -- FK
        rolls_roll_number uuid not null unique,            -- FK
        primary key (product_model_id, rolls_roll_number)
    )
    alter table if exists roll_model 
       add constraint FKc2fgr7j79edmcolp0elfhqit3 
       foreign key (article_article_code) 
       references tb_article_model
    alter table if exists tb_article_model 
       add constraint FK11ojre7jnbvyxaq9hu7vixgsw 
       foreign key (cor_color_code) 
       references tb_color
    alter table if exists tb_products_in_stock_rolls 
       add constraint FKf7gu54rqt0rwt5977edwy74kb 
       foreign key (rolls_roll_number) 
       references roll_model
    alter table if exists tb_products_in_stock_rolls 
       add constraint FKfovrka47vy4b05wxsi191q07h 
       foreign key (product_model_id) 
       references tb_products_in_stock

Aqui um teste para exemplificar:

    @Test
    void createProduct() {
        // 1. Criar uma Cor
        var color = new ColorModel();
        color.setColorCode(UUID.randomUUID());
        color.setColorName("Pantone Mango Tango");
        colorRepository.save(color);
        // 2. Criar um Artigo contendo sua respectiva Cor
        var article = new ArticleModel();
        article.setArticleCode(UUID.randomUUID());
        article.setArticleName("Soft cotton");
        article.setCor(color);
        articleRepository.save(article);
        // 3. Criar varios Rolos contendo seus respectivos Artigo
        var roll = new RollModel();
        roll.setRollNumber(UUID.randomUUID());
        roll.setArticle(article);
        rollRepository.save(roll);
        // 4. Criar um Produto contendo seus respectives Rolos
        var product = new ProductModel();
        product.setId(UUID.randomUUID());
        product.getRolls().add(roll);
        productRepository.save(product);
    }

Aqui um pull request para demonstrar: https://github.com/tadeupinheiro/api-stock-input-spring-boot/pull/1

Bom, se entendi direito os requisitos, esta seria a minha sugestao.

2

Entendi perfeitamente!

Só uma observação: o produto é o rolo.

No caso, o negócio é assim:

Se criaria todos os artigos e cores pois são um padrão. Não sei bem explicar ao certo, mas seria algo mais como "abstrato". Tipo, existe o cadastro deles no DB, mas não seriam algo tangível. Eu não poderia vender o artigo ou a cor, por exemplo.
Eu vendo o rolo, que é o produto. O rolo é do tipo(artigo) UNIPACIFIC, composição Y, etc.., cor código 0005, cor nome z.

A forma que ficaria mais clara, eu acho, é que: o estoque de artigos e cores não existe. Só existe o cadastro deles.

Já o estoque de Rolos sim, os artigos e cores só comporiam as especificações do rolo. (Daí que eu tirei a tentativa de fazer composição, no momento fez sentido na minha cabeça).

Para criar o produto/rolo não conseguiría só passar o id e deixar o backend cuidar do resto, pois os atributos do rolo só existe no romaneio de chegada dos produtos.
Exemplo: tamanho, número do rolo(é o id porque esse número é exclusivo por rolo), etc...

Eu consegui desenvolver o que queria, estou partindo agora para os métodos http. Até já fiz o post do artigo.

Se for do seu interesse ver o progresso, lá no repositório que te passei, voltei pra branch "main".

Sou imensamente grato pela tua atenção cara. O mais massa da área de tecnologia é a comunidade! Não sei como é no "trabalho", mas pelo menos online, a experiência é muito show.