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

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

问题描述

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

创建这样的界面:

 公共接口CountryRepository扩展了CrudRepository< Country,Long>{} 

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

 公共接口AbstractCatalogRepository扩展了CrudRepository< AbstractCatalog,Long>{} 

现在,保存时我没有看到任何问题,但是如果我要搜索 AbstractCatalog ,我已经确定会遇到麻烦,因为存储库将不知道哪个子目录-必须选择的班级.

AbstractCatalog.class

  @MappedSuperclass公共抽象类AbstractCatalog扩展了PersistentEntity {/***常量serialVersionUID.*/私有静态最终长serialVersionUID = 1L;@ID@GeneratedValue(策略= GenerationType.AUTO)私有整数ID;/*** 编码.*/@Column(唯一=真,可空=假,可更新=假)私有字符串代码;/*** 说明.*/@Column(nullable = false)私有字符串描述;/***正在使用中.*/@Column(名称="IN_USE",可为空=否,columnDefinition =位默认值1")private Boolean inUse = Boolean.TRUE;//吸气剂和吸气剂} 

Country.class

  @Entity@Table(名称="tc_country")@AttributeOverrides({@AttributeOverride(名称="id",列=@Column(name =" COUNTRY_SID"))),@AttributeOverride(名称=代码",列=@Column(name =" COUNTRY_CODE"))),@AttributeOverride(名称=描述",列=@Column(name =" COUNTRY_DESCRIPTION&qu​​ot;))})公共类Country扩展AbstractCatalog {public static final int MAX_CODE_LENGTH = 11;@Column(名称="GEONAMEID",可为空=真,唯一=假)私有Long geonameid;//getter和setter} 

有谁知道,我如何只使用一个存储库用于 AbstractCatalog 类的所有实现,而不必一遍又一遍地创建相同的接口,而名称和其他属性的差异却很小?/p>

解决方案

如果您不在数据库端使用表继承(例如,具有和此处

注意:此答案中的所有内容均针对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天全站免登陆