当前位置: 首页 > 知识库问答 >
问题:

是否有一种方法可以创建一个基于多个数据库表的JPA实体?我是否真的必须这样做,或者这是一种不好的做法?

陈实
2023-03-14

我对Spring Data JPA技术相当陌生,目前面临一个我无法处理的任务。我正在为这种情况寻求最佳实践。

在我的Postgres数据库中,我有一个一对多关系连接的两个表。表“account”有一个字段“type_id”,该字段是对表“account_type”字段“id”的外键引用:

因此,'account_type'表只起到字典的作用。因此,我创建了JPA实体(Kotlin代码):

@Entity
class Account(
  @Id @GeneratedValue var id: Long? = null,
  var amount: Int,
  @ManyToOne var accountType: AccountType
)
@Entity
class AccountType(
  @Id @GeneratedValue var id: Long? = null,
  var type: String
)

在我的Spring Boot应用程序中,我希望有一个RestConroller,它将负责以JSON格式提供所有帐户。为此,我将实体类序列化,并编写了一个简单的RESTController:

@GetMapping("/getAllAccounts", produces = [APPLICATION_JSON_VALUE])
fun getAccountsData(): String {
    val accountsList = accountRepository.findAll().toMutableList()
    return json.stringify(Account.serializer().list, accountsList)
}

其中accountRepository只是扩展CrudRepository 接口

现在,如果我转到:8080/getallaccounts,我将得到以下格式的Json(很抱歉格式化):

[
  {"id":1,
   "amount":0,
   "accountType":{
      "id":1,
      "type":"DBT"
     }
  },
  {"id":2,
    "amount":0,
    "accountType":{
       "id":2,
       "type":"CRD"
      }
   }
]

但我真正想从那个控制器那里得到的只是

[
   {"id":1,
    "amount":0,
    "type":"DBT"
   },
   {"id":2,
    "amount":0,
    "type":"CRD"
   }
]

当然,我可以为具有String字段而不是AccountType字段的帐户创建新的可序列化类,并可以将JPA Account类映射到该类,从AccountType字段提取帐户类型字符串。但对我来说,这看起来像是不必要的开销,我相信可以有一个更好的模式来处理这种情况。

例如,我脑子里想的是,我可能会以某种方式创建一个JPA实体类(使用表示帐户类型的字符串字段),它将基于两个数据库表,并且每次调用存储库方法时,具有内部对象的不必要的复杂性将自动降低:)此外,我将能够在业务逻辑中使用这个实体类,而不需要任何额外的“包装器”。

附言。我读过@secondarytable注释,但它似乎只能在两个表之间存在一对一关系的情况下工作,这不是我的情况。

共有1个答案

吴胜涝
2023-03-14

whic允许没有DTO的清洁分离有几个选项。

首先,您可以考虑使用一个投影,它有点像其他答案中提到的DTO,但没有许多缺点:

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections

@Projection(
  name = "accountSummary", 
  types = { Account.class }) 
public Interface AccountSummaryProjection{

    Long getId();

    Integer getAmount();

    @Value("#{target.accountType.type}")
    String getType();
}
@GetMapping("/getAllAccounts", produces = [APPLICATION_JSON_VALUE])
@ResponseBody
fun getAccountsData(): List<AccountSummaryProjection>{
    return accountRepository.findAllAsSummary();
}
@Entity
class Account(

  //in real life I would apply these using a Jacksin mix
  //to prevent polluting the domain model with view concerns.
  @JsonDeserializer(converter = StringToAccountTypeConverter.class)
  @JsonSerializer(converter = AccountTypeToStringConverter.class
  @Id @GeneratedValue var id: Long? = null,
  var amount: Int,
  @ManyToOne var accountType: AccountType
)

然后只需创建必要的转换器:

public class StringToAccountTypeConverter extends StdConverter<String, CountryType> 
           implements org.springframework.core.convert.converter.Converter<String, AccountType> {

  @Autowired
  private AccountTypeRepository repo;

  @Override
  public AccountType convert(String value) {
      //look up in repo and return
  }
}

反之亦然:

public class AccountTypeToStringConverter extends StdConverter<String, CountryType> 
           implements org.springframework.core.convert.converter.Converter<AccountType, String> {

  @Override
  public String convert(AccountType value) {
      return value.getName();
  }
}
 类似资料:
  • 我有一个粒子模拟项目,我已经工作了很多个小时,我将发布两个类。一个是粒子类,一个是main和Canvas类。我创建一个画布,然后得到它的BufferStrategy和一个Graphics在上面绘制。我使用更新循环来更新每一帧的粒子,并使用渲染循环来渲染每一帧的粒子。更新和渲染都是通过调用粒子数组列表中每个粒子的自渲染和自更新方法来完成的。现在这是我的问题。我有一个MouseListener,它在中

  • 问题内容: 有没有 在Python中,还是实现这种循环结构的好方法? 问题答案: Python中没有do-while循环。 这是类似的构造,取自上面的链接。

  • 我可以检查一个帐户是否是一个广告组的成员,但有没有办法告诉一个帐户是否属于一个OU?我想搜索由你而不是由广告组,我不确定如果这是可能的。下面是我如何搜索一个广告组。

  • 判断一个数是否为素数 思路说明 这个问题有多种解法,以下的解法来自网络整理。供参考使用。 解决(Python) #! /usr/bin/env python #coding:utf-8 """ """ #方法一 import math def isPrime1(n): if n <= 1: return False for i in range(2, int(

  • 问题内容: 如果使用Sun的专有Java类,则编译器将显示警告。我认为使用这些类通常不是一个好主意。我在某处阅读过。但是,除了警告之外,还有其他根本原因不建议您使用它们? 问题答案: 因为它们是内部API,所以它们可能会以未记录或不受支持的方式进行更改,并且已绑定到特定的JRE / JDK(在您的情况下为Sun),从而限制了程序的可移植性。 尽量避免使用此类API,请始终偏爱公开记录和指定的类。