2011-11-13 15 views
12

? He leído que es útil usar el patrón de generador cuando se tiene una clase con muchos parámetros. Me pregunto cómo puedes implementar una entidad usando un patrón de generador. Sería genial si puedes proporcionar un código de muestra.¿Cómo se puede utilizar el patrón de generador para las entidades con JPA

+2

por qué es importante que la clase es una entidad? ¿Por qué usar el patrón del generador para construir entidades es diferente de usarlo para construir cualquier otra cosa? –

+0

Quiero que sea una entidad, para poder almacenarlo en db. –

Respuesta

5

Por supuesto, es posible, solo tiene que proporcionar un Constructor (posiblemente anidado) para cada Entidad.

Aquí es un ejemplo de trabajo:

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 

@Entity 
public class FluentEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 
    private String someName; 
    private int someNumber; 
    private boolean someFlag; 

    protected FluentEntity(){} 

    private FluentEntity(String someName, int someNumber, boolean someFlag) { 
     this.someName = someName; 
     this.someNumber = someNumber; 
     this.someFlag = someFlag; 
    } 

    public long getId() { 
     return id; 
    } 

    public String getSomeName() { 
     return someName; 
    } 

    public int getSomeNumber() { 
     return someNumber; 
    } 

    public boolean isSomeFlag() { 
     return someFlag; 
    } 

    public static FluentEntityBuilder builder() { 
     return new FluentEntityBuilder(); 
    } 

    public static class FluentEntityBuilder { 

     private String someName; 
     private int someNumber; 
     private boolean someFlag; 

     public FluentEntityBuilder setSomeName(final String someName) { 
      this.someName = someName; 
      return this; 
     } 

     public FluentEntityBuilder setSomeNumber(final int someNumber) { 
      this.someNumber = someNumber; 
      return this; 
     } 

     public FluentEntityBuilder setSomeFlag(final boolean someFlag) { 
      this.someFlag = someFlag; 
      return this; 
     } 

     public FluentEntity build() { 
      return new FluentEntity(someName, someNumber, someFlag); 
     } 

    } 

} 

El código para utilizar sería la siguiente:

FluentEntity entity = FluentEntity.builder().setSomeName(someName).setSomeNumber(someNumber) 
       .setSomeFlag(someFlag).build(); 

Hemos de tener en cuenta que hay que excluir a los campos generados automáticamente como la clave principal (en este caso de ejemplo, el id) si tiene alguno.

Si desea deshacerse del código "estándar" para crear clases de Generador para cada Entidad, recomendaría una biblioteca de conveniencia, algo así como lombok. Luego obtendrá sus constructores (y aún más) anotando sus Entidades, tal vez cuesta un poco más de trabajo excluir los campos de id.

Usted debe echar un vistazo a Project Lombok

Sin embargo, he aquí algo de código para probar este constructor (implementado con Spring e Hibernate Boot).

El repositorio:

import org.springframework.data.repository.CrudRepository; 

import com.example.model.FluentEntity; 

public interface FluentEntityRepository extends CrudRepository<FluentEntity, Long> { 

} 

Y aquí hay algunas pruebas:

import static org.hamcrest.CoreMatchers.is; 
import static org.hamcrest.CoreMatchers.notNullValue; 
import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.greaterThan; 

import java.util.stream.StreamSupport; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.test.context.SpringBootTest; 
import org.springframework.test.context.junit4.SpringRunner; 
import org.springframework.transaction.annotation.Transactional; 

import com.example.model.FluentEntity; 

@RunWith(SpringRunner.class) 
@Transactional 
@SpringBootTest 
public class FluentEntityRepositoryTests { 

    @Autowired 
    private FluentEntityRepository fluentEntityRepository; 

    @Test 
    public void insertAndReceiveFluentEntityCreatedWithBuilder() { 
     final String someName = "name"; 
     final int someNumber = 1; 
     final boolean someFlag = true; 

     FluentEntity entity = FluentEntity.builder().setSomeName(someName).setSomeNumber(someNumber) 
       .setSomeFlag(someFlag).build(); 

     entity = fluentEntityRepository.save(entity); 
     assertThat("Entity did not get an generated Id!", entity.getId(), greaterThan(-1L)); 
     assertThat("Entity name did not match!", entity.getSomeName(), is(someName)); 
     assertThat("Entity number did not match!", entity.getSomeNumber(), is(someNumber)); 
     assertThat("Entity flag did not match!", entity.isSomeFlag(), is(someFlag)); 
    } 

    @Test 
    public void insertSomeAndReceiveFirst() { 
     fluentEntityRepository.save(FluentEntity.builder().setSomeName("A").setSomeNumber(1).setSomeFlag(true).build()); 
     fluentEntityRepository 
       .save(FluentEntity.builder().setSomeName("B").setSomeNumber(2).setSomeFlag(false).build()); 
     fluentEntityRepository.save(FluentEntity.builder().setSomeName("C").setSomeNumber(3).setSomeFlag(true).build()); 

     final Iterable<FluentEntity> findAll = fluentEntityRepository.findAll(); 
     assertThat("Should get some iterable!", findAll, notNullValue()); 

     final FluentEntity fluentEntity = StreamSupport.stream(findAll.spliterator(), false).findFirst().get(); 
     assertThat("Should get some entity!", fluentEntity, notNullValue()); 
    } 

} 
+0

¿El marco JPA podrá "automáticamente" ('@ Autowire'?) Crear instancias de Entidades que tengan instaladores solo en el constructor? –

+1

No sé si recibí su pregunta, pero en general los incubadores no son necesarios si se utiliza el acceso de campo. Entonces el proveedor JPA no invoca a los instaladores y los constructores pueden ser suficientes para su código comercial. Consulte "2.2 Campos y propiedades persistentes" en: http://download.oracle.com/otn-pub/jcp/persistence-2_1-fr-eval-spec/JavaPersistence.pdf –

+0

Ok, pero la razón principal por la que quiero usar un constructor es para que pueda crear campos 'finales'. Si usa el acceso de campo, no puede hacer que sean definitivas, ¿verdad? –

Cuestiones relacionadas