![](/img/trans.png)
[英]Spring Data JPA + Hibernate: How do I use a repository on abstract super class for object retrieval?
[英]Use abstract super class as parameter for Spring data repository
我知道如何實現 spring 數據存儲庫,
創建一個這樣的界面:
public interface CountryRepository extends CrudRepository<Country, Long> {}
現在Country
是一個AbstractCatalog
,我的項目中有(很多)更多的目錄。
我想知道我是否只能制作一個適用於所有目錄的存儲庫:
public interface AbstractCatalogRepository extends CrudRepository<AbstractCatalog, Long> {}
現在我在保存時沒有發現問題,但是如果我想搜索AbstractCatalog
我已經確定我會碰壁,因為存儲庫不知道它必須選擇哪個子類。
@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
類的所有實現,而不必一遍又一遍地創建相同的接口,而名稱和其他屬性的差異最小?
如果您不在數據庫端使用表繼承(例如,帶有標識符列的超類表),AFAIK,並且基於閱讀JPA 教程,則無法完成此操作(即@MappedSuperclass
抽象類使用@MappedSuperclass
注釋)
映射的超類不能被查詢,也不能在 EntityManager 或 Query 操作中使用。 您必須在 EntityManager 或 Query 操作中使用映射超類的實體子類。 映射的超類不能是實體關系的目標
請注意,JPA 存儲庫抽象在幕后使用 EntityManager。 我做了一個簡單的測試,你會得到什么(在 Hibernate 實現的情況下)“ IllegalArgumentException : not an entity 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);
}
}
基本上,總而言之,如果您沒有表繼承,您嘗試做的將不起作用。 存儲庫的類類型需要是一個實體。 如果您的表沒有以這種方式設置用於繼承,則歸結為是否要更改表。 只是為了避免多個存儲庫可能有點多。
注意:此答案中的所有內容均針對 Hibernate 提供程序進行了測試
好的,新項目,我正在關注這個設置。
問題是:我們想添加附件,但附件可以是上傳文件、鏈接或郵件。
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;
}
}
Spring 數據倉庫的:
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<Attachment>
,並且它們在后面有正確的子類。
這意味着,您可以制作一個執行instanceof
的渲染器,並且您可以為每個子類自定義渲染。
缺點是,您仍然需要創建自定義的特定存儲庫,但僅當您想查詢子類中的特定屬性時,或者只需要 1 個特定實現而不是所有實現時。
你用的是什么數據庫?
如果是 JPA,請查看我可以使用 Spring Data JPA 的 MappedSuperClass 的所有子項使用通用存儲庫嗎?
如果是 Mongo,您需要正確調整 Jackson 多態配置http://wiki.fasterxml.com/JacksonPolymorphicDeserialization
所以這是可能的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.