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

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

问题描述

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



创建一个这样的界面:

  public interface CountryRepository扩展CrudRepository< Country,Long> {} 

现在国家 AbstractCatalog 我在矿山项目中有很多(很多)目录。

我想知道我是否可以创建一个适用于所有目录的存储库:

  public interface AbstractCatalogRepository扩展了CrudRepository< AbstractCatalog,Long> {} 

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



< h2> AbstractCatalog.class

  @MappedSuperclass 
公共抽象类AbstractCatalog扩展PersistentEntity {

/ **
* Constant serialVersionUID。
* /
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
/ **
*代码。
* /
@Column(unique = true,nullable = false,updatable = false)
private String code;
/ **
*描述。
* /
@Column(nullable = false)
private String description;
/ **
*正在使用中。
* /
@Column(name =IN_USE,nullable = false,columnDefinition =bit default 1)
private Boolean inUse = Boolean.TRUE;

// getter 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 的所有实现做一次回购而不用一次又一次地创建相同的接口只需要对名称和实现类进行最小的更改?

解决方案

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



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


I know the implementation of spring data repository's :

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 mine project.
I'm wondering if I can make 1 repository that should work for all the catalogs :

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

Now with save I don't see directly a problem but if I want to search an AbstractCatalog I'm already sure I'll hit the wall cause the repo will not know from what object he 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 an idea how I could just make 1 Repo for all the implementations of AbstractCatalog without to create the same interface over and over again with just the minimal change of name and implementation class?

解决方案

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天全站免登陆