具有Inheritance.JOINED的Spring数据存储库 [英] Spring Data Repository with Inheritance.JOINED

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

问题描述

我在应用程序中设计了实体,以遵循 Hibernate的继承策略Inheritance.JOINED.

基本抽象类是UserTable,具体派生类是ClientTableOwnerTable.

我要实现的目标是拥有一个单一的存储库,在其中可以通过IdEmail find任意UserTable(ClientTableOwnerTable).重要的要求是,一旦获取它们就可以将其强制转换为正确的类型,并且它们必须携带其特定的字段(而不仅仅是从UserTable继承的字段).

同样重要的是,我应该能够通过相同的存储库来持久化那些实体. repository.save(clientTable).

所以这样的事情应该是可能的:

UserTableRepository repository = // ...

int clientId = 3; 
int ownerId = 5;

ClientTable clientTable = (ClientTable) repository.findByUserId(clientId);
OwnerTable clientTable = (OwnerTable) repository.findByUserId(ownerId);

clientTable = (ClientTable) repository.findByEmail(clientEmail);
ownerTable = (OwnerTable) repository.findByEmail(ownerEmail);

我的实体看起来像这样.

UserTable.java

@Entity
@Table(name = "USER")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class UserTable implements Serializable {

    @Column(name = "USER_ID", nullable = false)
    private Long userId;

    @EmbeddedId
    private UserTablePK userTablePK;

    @Column(name = "PASSWORD", nullable = false, length = 512)
    private String password;

    @Column(name = "FIRSTNAME", nullable = false, length = 256)
    private String firstName;

    // get, set
}

..和主键

UserTablePK.java

@Embeddable
public class UserTablePK implements Serializable {

    private static final long serialVersionUID = 1L;

    @Column(name = "EMAIL", nullable = false, length = 256)
    private String email;

    public UserTablePK() {
    }

    public UserTablePK(String email) {
        this.email = email;
    }

    // get, set
}

ClientTable.java

@Entity
@Table(name = "CLIENT")
public class ClientTable extends UserTable implements Serializable {

    @Column(name = "SHOPING_POWER")
    private Integer shoppingPower;

    @Column(name = "SHOPPING_FREQUENCY")
    private Integer shoppingFreq;
    
    // get, set
}

OwnerTable.java

@Entity
@Table(name = "OWNER")
public class OwnerTable extends UserTable implements Serializable {

    @Column(name = "EFFICIENCY")
    private String efficiency;

    @Column(name = "SALARAY")
    private Integer;

    // get, set
}

现在,一旦设置了实体,我就需要编写一个类似于上述操作的存储库,这是我需要帮助的地方.我当时想写这样的东西.

UserTableRepository.java

@Repository
public interface UserTableRepository extends CrudRepository<UserTable, UserTablePK> {

    @Query("SELECT e FROM UserTable e WHERE e.userTablePK.email = ?1")
    public UserTable findByEmail(String email); // if owner email, retrieve OwnerTable; if client email, retrieve ClientTable instance

    @Query("SELECT e FROM UserTable e WHERE e.userId = ?1")
    public UserTable findByUserId(Long userId); // if owner id, retrieve OwnerTable; if client id, retrieve ClientTable instance
}

我实际上还没有尝试过,因为我想检查这是否是正确的方法,但是:我相当怀疑此Query是否有效.因为要检索整个子类对象,应使用某种JOIN,而问题是我不能明确地说出ie. JOIN ClientTable,因为那样我将无法获取任何OwnerTable实体.

如何实现可以从同一个存储库中获取两个子类?

更新

此外,要求是能够获取特定子类.像这样:

List<ClientTable> clients = repository.findAllClients();

是否可以使用相同的存储库,还是应该编写特定于子类的存储库?例如.

@Repository
public interface ClientTableRepository extends CrudRepository<ClientTable, ClientTablePK> {
 // empty
}

...然后像这样称呼他们

ClientTableRepository repository = // ...

List<ClientTable> clients = repository.findAll();

JPA是否足以确定如何查找特定子类的所有实例是否足够?

解决方案

您想要实现的正是JPA中继承的工作原理.

因此,您的查询非常好,结果列表中将包含子类的实例.

在我的一篇博客文章中了解有关JPA继承的更多信息:

https://72.services/inheritance-in-jpa/

I have designed the entities in my application to follow the Hibernate's inheritance strategy Inheritance.JOINED.

The base abstract class is UserTable and the concrete derived classes are ClientTable and the OwnerTable.

The thing that I want to achieve is to have a single repository in which I could find any UserTable (both ClientTable and OwnerTable) by the Id or Email. The important requirement is that they can be cast to the correct type once they are fetched, and that they carry their specific fields (and not just the ones inherited from UserTable).

Equally important, I should be able to persist those entities through the same repository, ie. repository.save(clientTable).

So something like this should be possible:

UserTableRepository repository = // ...

int clientId = 3; 
int ownerId = 5;

ClientTable clientTable = (ClientTable) repository.findByUserId(clientId);
OwnerTable clientTable = (OwnerTable) repository.findByUserId(ownerId);

clientTable = (ClientTable) repository.findByEmail(clientEmail);
ownerTable = (OwnerTable) repository.findByEmail(ownerEmail);

My entities look like this.

UserTable.java

@Entity
@Table(name = "USER")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class UserTable implements Serializable {

    @Column(name = "USER_ID", nullable = false)
    private Long userId;

    @EmbeddedId
    private UserTablePK userTablePK;

    @Column(name = "PASSWORD", nullable = false, length = 512)
    private String password;

    @Column(name = "FIRSTNAME", nullable = false, length = 256)
    private String firstName;

    // get, set
}

.. and a primary key

UserTablePK.java

@Embeddable
public class UserTablePK implements Serializable {

    private static final long serialVersionUID = 1L;

    @Column(name = "EMAIL", nullable = false, length = 256)
    private String email;

    public UserTablePK() {
    }

    public UserTablePK(String email) {
        this.email = email;
    }

    // get, set
}

ClientTable.java

@Entity
@Table(name = "CLIENT")
public class ClientTable extends UserTable implements Serializable {

    @Column(name = "SHOPING_POWER")
    private Integer shoppingPower;

    @Column(name = "SHOPPING_FREQUENCY")
    private Integer shoppingFreq;
    
    // get, set
}

OwnerTable.java

@Entity
@Table(name = "OWNER")
public class OwnerTable extends UserTable implements Serializable {

    @Column(name = "EFFICIENCY")
    private String efficiency;

    @Column(name = "SALARAY")
    private Integer;

    // get, set
}

Now once the entities are set, I need to write a repository that would act like described above, and here is where I need some help. I was thinking to write something like this.

UserTableRepository.java

@Repository
public interface UserTableRepository extends CrudRepository<UserTable, UserTablePK> {

    @Query("SELECT e FROM UserTable e WHERE e.userTablePK.email = ?1")
    public UserTable findByEmail(String email); // if owner email, retrieve OwnerTable; if client email, retrieve ClientTable instance

    @Query("SELECT e FROM UserTable e WHERE e.userId = ?1")
    public UserTable findByUserId(Long userId); // if owner id, retrieve OwnerTable; if client id, retrieve ClientTable instance
}

I didn't actually try this yet, because I want to check if this is even the right route to take, but: I am rather skeptical that this Query would work. Because in order to retrieve the whole subclass object, some kind of JOIN should be used, and the problem is that I can't explicitly say ie. JOIN ClientTable because then I would not be able to fetch any OwnerTable entities.

How can I achieve that I can fetch both subclasses from the same repository?

UPDATE

Also, the requirement is to be able to fetch for the specific subclass. So something like:

List<ClientTable> clients = repository.findAllClients();

Is that possible using the same repository, or should I write repositories specific for subclasses? For example.

@Repository
public interface ClientTableRepository extends CrudRepository<ClientTable, ClientTablePK> {
 // empty
}

... and then call them like:

ClientTableRepository repository = // ...

List<ClientTable> clients = repository.findAll();

Would that be enough for the JPA to determine how to find all the instances of just a specific subclass?

解决方案

What you want to achieve is exactly how inheritance in JPA works.

So your queries are perfectly fine and you will have instances of the subclasses in the result list.

Read more about JPA inheritance in one of my blog posts:

https://72.services/inheritance-in-jpa/

这篇关于具有Inheritance.JOINED的Spring数据存储库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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