gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 12:37:57 25 4
gpt4 key购买 nike

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

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

schema image

所以'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<Account, Long> 的接口(interface).

现在如果我去 :8080/getAllAccounts ,我会得到以下格式的Json(抱歉格式化):
[
{"id":1,
"amount":0,
"accountType":{
"id":1,
"type":"DBT"
}
},
{"id":2,
"amount":0,
"accountType":{
"id":2,
"type":"CRD"
}
}
]

但我真正想从那个 Controller 那里得到的只是
[
{"id":1,
"amount":0,
"type":"DBT"
},
{"id":2,
"amount":0,
"type":"CRD"
}
]

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

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

附:我读到了 @SecondaryTable 注释,但它看起来只能在两个表之间存在一对一关系的情况下才有效,这不是我的情况。

最佳答案

有几个选项可以在没有 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();
}

然后,您只需更新您的 Controller 以调用具有 List 返回类型的查询方法或编写一个将 proection 类作为 arg 的方法。

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projection.dynamic
@GetMapping("/getAllAccounts", produces = [APPLICATION_JSON_VALUE])
@ResponseBody
fun getAccountsData(): List<AccountSummaryProjection>{
return accountRepository.findAllAsSummary();
}

另一种方法是使用 Jackson 注释。我在您的问题中注意到您正在手动将结果转换为 JSON 字符串并从 Controller 返回一个字符串。如果 Jackson Json 库位于类路径中,则不需要这样做。请参阅上面的 Controller 。

因此,如果您将序列化留给 Jackson,您可以使用几个注释将 View 与实体分开。请注意,我将使用 Jackson mixin 应用这些,而不必使用 Json 处理指令污染实体模型,但是您可以查看:
@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();
}
}

关于spring - 有没有一种方法可以基于许多数据库表创建一个 JPA 实体,我真的必须这样做还是一种不好的做法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60328741/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com