tutorial que pagingandsortingrepository findbyid ejemplos ejemplo data curso java spring jpa spring-data-jpa

java - que - spring jpa curso



Utilice la súper clase abstracta como parámetro para el repositorio de datos Spring (3)

Conozco la implementación del repositorio de datos de Spring:

Crea una interfaz como esta:

public interface CountryRepository extends CrudRepository<Country, Long> {}

Ahora Country es un AbstractCatalog y tengo (muchos) más catálogos en mi proyecto.
Me pregunto si puedo hacer un repositorio que funcione para todos los catálogos:

public interface AbstractCatalogRepository extends CrudRepository<AbstractCatalog, Long> {}

Ahora, con guardar, no veo directamente un problema, pero si quiero buscar en un AbstractCatalog ya estoy seguro de que golpearé la pared porque el representante no sabrá de qué objeto debe elegir.

AbstractCatalog.class

@MappedSuperclass public abstract class AbstractCatalog extends PersistentEntity { /** * The Constant serialVersionUID. */ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; /** * The code. */ @Column(unique = true, nullable = false, updatable = false) private String code; /** * The description. */ @Column(nullable = false) private String description; /** * The in use. */ @Column(name = "IN_USE", nullable = false, columnDefinition = "bit default 1") private Boolean inUse = Boolean.TRUE; // getters and setters }

Clase de pais

@Entity @Table(name = "tc_country") @AttributeOverrides({ @AttributeOverride(name = "id", column = @Column(name = "COUNTRY_SID")), @AttributeOverride(name = "code", column = @Column(name = "COUNTRY_CODE")), @AttributeOverride(name = "description", column = @Column(name = "COUNTRY_DESCRIPTION"))}) public class Country extends AbstractCatalog { public static final int MAX_CODE_LENGTH = 11; @Column(name = "GEONAMEID", nullable = true, unique = false) private Long geonameid; // getter and setter }

¿Alguien tiene una idea de cómo podría hacer 1 Repo para todas las implementaciones de AbstractCatalog sin crear la misma interfaz una y otra vez con solo el cambio mínimo de nombre y clase de implementación?



Oke, nuevo proyecto y estoy siguiendo esta configuración un poco.
El problema fue: queremos agregar archivos adjuntos, pero un archivo adjunto puede ser cargar un archivo, un enlace o un correo.

Clases de pojo:

Attachment.java:

@Entity @Table(name = "T_ATTACHMENT") @Inheritance(strategy = InheritanceType.JOINED) @DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING) public abstract class Attachment { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "ATTACHMENT_SID") private Long id; @ManyToOne @JoinColumn(name = "TASK_SID", referencedColumnName = "TASK_SID", nullable = false, unique = false, insertable = true, updatable = true) private Task task; @ManyToOne @JoinColumn(name = "USER_SID", referencedColumnName = "USER_SID", nullable = false, unique = false, insertable = true, updatable = true) private User user; public Task getTask() { return task; } public void setTask(Task task) { this.task = task; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }

FileAttachment.java:

@Entity @Table(name = "T_FILE_ATTACHMENT") @DiscriminatorValue("FILE") public class FileAttachment extends Attachment { @Column(name = "NAME", nullable = false, unique = false) private String fileName; @Lob @Basic @Column(name = "FILE", nullable = false, unique = false) private byte[] file; public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public byte[] getFile() { return file; } public void setFile(byte[] file) { this.file = file; } }

MailAttachment.java:

@Entity @Table(name = "T_MAIL_ATTACHMENT") @DiscriminatorValue("MAIL") public class MailAttachment extends Attachment { @Column(name = "RECIPIENT", nullable = false, unique = false) private String to; @Column(name = "CC", nullable = true, unique = false) private String cc; @Column(name = "BCC", nullable = true, unique = false) private String bcc; @Column(name = "TITLE", nullable = true, unique = false) private String title; @Column(name = "MESSAGE", nullable = true, unique = false) private String message; public String getTo() { return to; } public void setTo(String to) { this.to = to; } public String getCc() { return cc; } public void setCc(String cc) { this.cc = cc; } public String getBcc() { return bcc; } public void setBcc(String bcc) { this.bcc = bcc; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }

LinkAttachment.java:

@Entity @Table(name = "T_LINK_ATTACHMENT") @DiscriminatorValue("LINK") public class LinkAttachment extends Attachment { @Column(name = "DESCRIPTION", nullable = true, unique = false) private String description; @Column(name = "LINK", nullable = false, unique = false) private String link; public String getDescription() { return description == null ? getLink() : description; } public void setDescription(String description) { this.description = description; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } }

Repos de datos de primavera:

AttachmentRepository.java:

public interface AttachmentRepository extends CustomRepository<Attachment, Long> { List<Attachment> findByTask(Task task); }

CustomRepository.java:

public interface CustomRepository<E, PK extends Serializable> extends PagingAndSortingRepository<E, PK>, JpaSpecificationExecutor<E>, QueryDslPredicateExecutor<E> { @Override List<E> findAll(); }

Y por fin el servicio.

@Service public class AttachmentServiceImpl implements AttachmentService { @Inject private AttachmentRepository attachmentRepository; @Override public List<Attachment> findByTask(Task task) { return attachmentRepository.findByTask(task); } @Override @Transactional public Attachment save(Attachment attachment) { return attachmentRepository.save(attachment); } }

Esto resulta en :

Puedo guardar en el repositorio abstracto con cualquier implementación que creé, JPA lo hará correctamente.

Si llamo a findByTask(Task task) , obtengo una List<Attachment> de todas las subclases, y tienen la subclase correcta en la parte posterior.
Esto significa que puede crear un renderizador que ejecute instanceof y puede personalizar su representación para cada subclase.

El inconveniente es que aún necesita crear repositorios específicos personalizados, pero solo cuando desea consultar en una propiedad específica qué hay en la subclase o cuando solo desea una implementación específica en lugar de todas las implementaciones.


Si no está utilizando la herencia de tablas en el lado de la base de datos (por ejemplo, una tabla de superclase con una columna descriminadora ), AFAIK, y no está basado en la lectura del tutorial de JPA , esto no puede hacerse (es decir, simplemente utilizando la anotación @MappedSuperclass para su clase abstracta)

Las superclases asignadas no se pueden consultar y no se pueden usar en EntityManager o en las operaciones de consulta. Debe utilizar las subclases de entidad de la superclase asignada en EntityManager o en las operaciones de consulta. Las superclases asignadas no pueden ser objetivos de relaciones de entidad

Tenga en cuenta que la abstracción del repositorio JPA utiliza un EntityManager debajo del capó. Hice una prueba simple, y lo que obtendrá (en el caso de la implementación de Hibernate) una " IllegalArgumentException : not an entity AbstractClass "

Por otro lado, si usa la herencia de tablas, entonces puede usar el tipo abstracto. Sé que usted dijo "con solo el mínimo cambio" (y creo que mi respuesta corta es que no creo que sea posible, probablemente por las razones que adivinó), por lo que supongo que el resto de esta respuesta es para otras mentes inquisitivas; )

Un ejemplo de una estrategia de herencia de tablas sería algo como esto (exención de responsabilidad: esta no es la visualización correcta para la herencia erd, pero MySQL Workbench no lo admite, pero lo que he hecho a continuación ha diseñado el modelo para MYSQL de la forma que necesita. ser)

Donde CountryCatalog tiene una referencia FK / PK a la tabla AbstractCatalog pk (id). La tabla AbstractCatalog tiene un descriminatorColumn que se usará para determinar a qué subtipo se relaciona la ocurrencia de supertipo.

En términos de cómo codificarías eso, se vería algo así como

@Entity @Inheritance(strategy = InheritanceType.JOINED) @DiscriminatorColumn(name="descriminatorColumn") @Table(name="AbstractCatalog") public abstract class AbstractCatalog { @Id private long id; ... } @Entity @Table(name = "CountryCatalog") public class CountryCatalog extends AbstractCatalog { // id is inherited ... } public interface AbstractCatalogRepository extends JpaRepository<AbstractCatalog, Long> { } @Repository public class CountryCatalogServiceImpl implements CountryCatalogService { @Autowired private AbstractCatalogRepository catalogRepository; @Override public List<CountryCatalog> findAll() { return (List<CountryCatalog>)(List<?>)catalogRepository.findAll(); } @Override public CountryCatalog findOne(long id) { return (CountryCatalog)catalogRepository.findOne(id); } }

Básicamente, en conclusión, lo que está tratando de hacer no funcionará si no tiene herencia de tablas. El tipo de clase para el repositorio debe ser una entidad. Si sus tablas no están configuradas de esta manera para la herencia, solo se reduce a si desea o no cambiar las tablas. Sin embargo, puede ser demasiado para evitar varios repositorios.

Algunas referencias que he usado están aquí y aquí.

Nota: Todo en esta respuesta está probado contra el proveedor de Hibernate.