使用抽象超类作为Spring数据存储库的参数

我知道spring数据存储库的实现:

创建一个这样的界面:

public interface CountryRepository extends CrudRepository {} 

现在Country是一个AbstractCatalog目录,我在矿山项目中有很多(很多)目录。
我想知道我是否可以创建一个适用于所有目录的存储库:

 public interface AbstractCatalogRepository extends CrudRepository {} 

现在有了保存,我没有直接看到问题,但如果我想搜索一个AbstractCatalog我已经确定我会碰壁,因为回购不会知道他必须选择什么对象。

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 } 

Country.class

 @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所有实现做一个回购?

如果您没有在数据库端使用表inheritance(例如,带有descriminator列的超类表),AFAIK,并且基于阅读JPA教程 ,则无法完成此操作(即,只需对您的抽象类使用@MappedSuperclass注释)

无法查询映射的超类,也无法在EntityManager或Query操作中使用。 您必须在EntityManager或Query操作中使用映射的超类的实体子类。 映射的超类不能成为实体关系的目标

注意,JPA存储库抽象使用了一个EntityManager。 我做了一个简单的测试,你会得到什么(在Hibernate实现的情况下)“ IllegalArgumentException : not an entity AbstractClass

另一方面,如果使用表inheritance,则可以使用抽象类型。 我知道你说“只有最小的改变” (我想我的简短回答是我认为这不可能 – 可能是因为你猜对了的原因),所以我猜这个答案的其余部分是针对其他探究的人; – )

表inheritance策略的一个例子是这样的(免责声明:这不是erdinheritance的正确可视化 ,但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 { } @Repository public class CountryCatalogServiceImpl implements CountryCatalogService { @Autowired private AbstractCatalogRepository catalogRepository; @Override public List findAll() { return (List)(List)catalogRepository.findAll(); } @Override public CountryCatalog findOne(long id) { return (CountryCatalog)catalogRepository.findOne(id); } } 

基本上,总而言之,如果您没有表inheritance,那么您尝试执行的操作将无法正常工作。 存储库的类类型必须是实体。 如果您的表没有以这种方式设置inheritance,那么它只取决于您是否要更改表。 但是,避免多个存储库可能有点多。

我使用的一些参考文献在这里和这里

注意:此答案中的所有内容都是针对Hibernate提供程序进行测试的

哦,新项目,我正在关注这个设置。
问题是:我们想要添加附件,但附件可以上传文件,链接或邮件。

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

Spring数据仓库:

AttachmentRepository.java:

 public interface AttachmentRepository extends CustomRepository { List findByTask(Task task); } 

CustomRepository.java:

 public interface CustomRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, QueryDslPredicateExecutor { @Override List findAll(); } 

最后服务:

 @Service public class AttachmentServiceImpl implements AttachmentService { @Inject private AttachmentRepository attachmentRepository; @Override public List 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个特定实现而不是所有实现时。

你用的是什么数据库?

如果它是JPA,请看一下我可以使用Spring数据JPA为MappedSuperClass的所有子项使用通用存储库吗?

如果它是Mongo你需要正确调整Jackson多态性配置http://wiki.fasterxml.com/JacksonPolymorphicDeserialization

所以这是可能的。