使用抽象超类作为 Spring 数据存储库的参数 [英] Use abstract super class as parameter for Spring data repository

查看:26
本文介绍了使用抽象超类作为 Spring 数据存储库的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如何实现 spring 数据存储库,

创建一个这样的界面:

public interface CountryRepository extends CrudRepository{}

现在 Country 是一个 AbstractCatalog 并且我的项目中有(很多)更多的目录.
我想知道我是否只能创建一个适用于所有目录的存储库:

public interface AbstractCatalogRepository extends CrudRepository{}

现在我在保存时没有发现问题,但是如果我想搜索 AbstractCatalog 我已经确定我会撞墙,因为存储库不知道哪个子必须选择的类.

AbstractCatalog.class

@MappedSuperclass公共抽象类 AbstractCatalog 扩展 PersistentEntity {/*** 常量 serialVersionUID.*/private static final long serialVersionUID = 1L;@ID@GeneratedValue(策略 = GenerationType.AUTO)私有整数 ID;/*** 代码.*/@Column(unique = true, nullable = false, updateable = false)私人字符串代码;/*** 说明.*/@Column(可为空 = 假)私人字符串描述;/*** 在使用中.*/@Column(name = "IN_USE", nullable = false, columnDefinition = "bit default 1")私有布尔inUse = Boolean.TRUE;//getter 和 setter}

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"))})公共类国家扩展 AbstractCatalog {公共静态最终 int MAX_CODE_LENGTH = 11;@Column(name = "GEONAMEID", nullable = true, unique = false)私人 Long geonameid;//获取器和设置器}

有没有人知道如何只使用一个存储库来实现 AbstractCatalog 类的所有实现,而不必一遍又一遍地创建相同的界面,并且名称和其他属性的差异最小?

解决方案

如果您没有在数据库端使用表继承(例如带有 和这里

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

I know how to implement spring data repositories,

Create an interface like this :

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

Now Country is an AbstractCatalog and I have (a lot) more catalogs in my project.
I'm wondering if I can make only one repository that would work for all the catalogs:

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

Now I don't see a problem while saving, but if I want to search an AbstractCatalog I'm already sure that I'll hit the wall because the repository will not know which sub-class it must choose.

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
}

Has anyone any idea, how I could use only ONE repository for all the implementations of AbstractCatalog class without having to create the same interface over and over again with minimal differences in name and other properties?

解决方案

If you aren't using table inheritance on the database side (e.g. super class table with descriminator column), AFAIK, and based off reading the JPA tutorial, this can't be done (i.e. simply using @MappedSuperclass annotation for your abstract class)

Mapped superclasses cannot be queried and cannot be used in EntityManager or Query operations. You must use entity subclasses of the mapped superclass in EntityManager or Query operations. Mapped superclasses can't be targets of entity relationships

Note, the JPA repository abstraction uses an EntityManager under the hood. I did a simple test, and what you will get (in the case of Hibernate implementation) an "IllegalArgumentException : not an entity AbstractClass"

On the other hand, if you do use table inheritance, then you can use the abstract type. I know you said "with just the minimal change" (and I guess my short answer is I don't think it's possible - probably for the reasons you guessed), so I guess the rest of this answer is for other inquiring minds ;-)

An example of a table inheritance strategy would be something like this (disclaimer: this is not the correct visualization for erd inheritance, but MySQL Workbench doesn't support it, but what I have below forward engineered the model to MYSQL the way it needs to be)

Where CountryCatalog has a FK/PK reference to the AbstractCatalog table pk (id). The AbstractCatalog table has a descriminatorColumn that will be used to determine to which subtype the supertype occurrence is related.

In terms of how you would code that, it would look something like

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


Basically, in conclusion, what you are trying to do won't work if you don't have table inheritance. The class type for the repository needs to be an entity. If your tables aren't set up this way for inheritance, it just comes down to whether or not you want to change the tables. It may be a bit much just to avoid multiple repositories though.

Some references I used are here and here

Note: Everything in this answer is tested against Hibernate provider

这篇关于使用抽象超类作为 Spring 数据存储库的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆