복붙노트

[SPRING] Spring 데이터 저장소에 대한 매개 변수로 추상 수퍼 클래스 사용

SPRING

Spring 데이터 저장소에 대한 매개 변수로 추상 수퍼 클래스 사용

스프링 데이터 저장소의 구현을 알고 :

다음과 같은 인터페이스를 작성하십시오.

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

Now Country는 AbstractCatalog이고 저는 광산 프로젝트에 카탈로그를 많이 보유하고 있습니다. 모든 카탈로그에서 작동해야하는 저장소를 만들 수 있는지 궁금합니다.

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

이제 save를 사용하면 문제가 직접적으로 나타나지 않지만 Abstract Catalog를 검색하려면 repo가 ​​어떤 객체를 선택해야하는지 알 수 없으므로 벽을 치게 될 것입니다.

@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
}
@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
}

누구든지 최소한 AbstractCatalog의 모든 구현에 대해 이름과 구현 클래스의 최소한의 변경으로 동일한 인터페이스를 반복해서 만들지 않고도 1 Repo를 만들 수있는 아이디어가 있습니까?

해결법

  1. ==============================

    1.데이터베이스 측에서 테이블 상속 (예 : descriminator 열이있는 수퍼 클래스 테이블), AFAIK를 사용하지 않고 JPA 튜토리얼을 읽지 않는 경우 (즉, 추상 클래스에 @MappedSuperclass 주석을 사용하는 것)

    데이터베이스 측에서 테이블 상속 (예 : descriminator 열이있는 수퍼 클래스 테이블), AFAIK를 사용하지 않고 JPA 튜토리얼을 읽지 않는 경우 (즉, 추상 클래스에 @MappedSuperclass 주석을 사용하는 것)

    JPA 저장소 추상화는 내부적으로 EntityManager를 사용합니다. 나는 간단한 테스트를 수행했고 (Hibernate 구현의 경우) "IllegalArgumentException : 엔터티가 아닌 AbstractClass"를 얻을 것이다.

    반면에 테이블 상속을 사용하면 추상 유형을 사용할 수 있습니다. 나는 당신이 "최소한의 변화만으로"라고 말한 것을 알고있다. (그리고 아마도 나의 짧은 대답은 그것이 가능하다고 생각하지 않는다고 생각할 것이다 - 아마도 당신이 짐작했던 이유 때문일 것이다.) 그래서이 나머지 대답은 다른 탐구하는 마음을위한 것이라고 생각한다; )

    테이블 상속 전략의 예는 다음과 같습니다 (면책 조항 : erd 상속에 대한 올바른 시각화가 아니지만 MySQL Workbench는이를 지원하지 않습니다. 그러나 아래에서 내가 필요로하는 방식으로 모델을 MYSQL에 엔지니어링했습니다. 있다)

    여기서 CountryCatalog에는 AbstractCatalog 테이블 pk (id)에 대한 FK / PK 참조가 있습니다. AbstractCatalog 테이블에는 상위 유형이 연관된 하위 유형을 판별하는 데 사용되는 descriminatorColumn이 있습니다.

    어떻게 코딩 할 것인가와 관련해서는 다음과 같이 보일 것입니다.

    @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);
        }   
    }
    

    결론적으로 결론적으로, 당신이 테이블 상속이 없다면 당신이하려고하는 것은 작동하지 않을 것입니다. 저장소의 클래스 유형은 엔티티 여야합니다. 테이블이 상속을 위해이 방법으로 설정되지 않은 경우에는 테이블을 변경할지 여부 만 결정됩니다. 그것은 단지 여러 저장소를 피하기 위해 조금은 다를 수 있습니다.

    내가 사용한 몇 가지 참고 자료는 여기와 여기에 있습니다.

    참고 :이 대답의 모든 것은 최대 절전 모드 공급자에 대해 테스트됩니다.

  2. ==============================

    2.Oke, 새로운 프로젝트와 나는이 설정을 조금 따르고 있습니다. 문제는 : 첨부 파일을 추가하고 싶지만 첨부 파일은 파일, 링크 또는 메일을 업로드 할 수 있습니다.

    Oke, 새로운 프로젝트와 나는이 설정을 조금 따르고 있습니다. 문제는 : 첨부 파일을 추가하고 싶지만 첨부 파일은 파일, 링크 또는 메일을 업로드 할 수 있습니다.

    Pojo 강좌 :

    @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;
        }
    }
    
    @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;
        }
    }
    
    @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;
        }
    }
    
    @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;
        }
    }
    

    봄 데이터 저장소 :

    public interface AttachmentRepository extends CustomRepository<Attachment, Long> {    
        List<Attachment> findByTask(Task task);
    }
    
    public interface CustomRepository<E, PK extends Serializable> extends
                    PagingAndSortingRepository<E, PK>,
                    JpaSpecificationExecutor<E>, 
                    QueryDslPredicateExecutor<E> {
        @Override
        List<E> findAll();
    }
    

    그리고 마침내 서비스 :

    @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);
        }
    }
    

    결과는 다음과 같습니다.

    내가 만든 모든 구현으로 추상적 인 저장소에 저장할 수 있습니다. JPA는이를 올바르게 수행합니다.

    findByTask (Task task)를 호출하면 모든 서브 클래스의 List 가 생기고 뒤쪽에 올바른 서브 클래스가 생깁니다. 즉, instanceof를 수행하는 렌더러를 만들 수 있으며 각 하위 클래스의 렌더링을 사용자 정의 할 수 있습니다.

    단점은 여전히 ​​사용자 지정 저장소를 만들 필요가 있지만 하위 클래스에있는 특정 속성을 쿼리하거나 모든 구현 대신 특정 구현을 1 개만 원하는 경우에만 쿼리를 작성해야한다는 것입니다.

  3. ==============================

    3.어떤 DB를 사용하고 있습니까?

    어떤 DB를 사용하고 있습니까?

    JPA 인 경우 다음을 확인하십시오. Spring Data JPA에서 MappedSuperClass의 모든 자식에 대해 일반적인 저장소를 사용할 수 있습니까?

    Mongo라면 잭슨 다형성 구성을 적절하게 조정해야합니다. http://wiki.fasterxml.com/JacksonPolymorphicDeserialization

    그래서 이것은 가능합니다.

  4. from https://stackoverflow.com/questions/25237664/use-abstract-super-class-as-parameter-to-spring-data-repository by cc-by-sa and MIT license