【问题标题】:How to avoid updating or creating subentities when not required如何避免在不需要时更新或创建子实体
【发布时间】:2022-01-07 18:15:19
【问题描述】:

我是实体框架的新手,如果这看起来很愚蠢,请原谅我。

考虑以下 json 对象:

{
    "id": "8850a2d2-230e-8ecb-cbb8-06068df136aa",
    "fiscalCode": "QHNMPN27E68F765S",
    "role": {
        "id": "MED",
        "name": "Medico di base"
    },
    "enabled": true,
    "name": "Alessio",
    "surname": "De Padova",
    "contacts": [],
    "specs": [
        {
            "name": "Fisiatria",
            "id": "FISIA"
        },
         {
            "name": "Cardiologia",
            "id": "CARD"
        }
    ],
    "account": {
        "id": "5541",
        "email": "alessandro.spaghetti@gmail.com"
    },
    "submit": null
}

假设我们将其作为请求正文发送,以便在数据库中更新它。它是一个具有子实体的用户,如下所示:

@Id
@Column(name = "user_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;

@Column(name = "name")
@NotNull(message = "Name cannot be null")
@Size(min = 1, message = "Name is not long enough")
private String name;

@Column(name = "fiscal_code")
@NotNull(message = "Fiscal code cannot be null")
@Size(min=16, max=16, message = "Fiscal code has to be 16 chars long")
private String fiscalCode;

@Column(name = "enabled")
private Boolean enabled;

@Column(name = "surname")
@Size(min = 1, message = "Surname is not long enough")
@NotNull(message = "Surname cannot be null")
private String surname;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "account_id")
private AccountEntity account;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "role_id")
private RoleEntity role;

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private Set<ContactEntity> contacts;

@OneToMany(cascade = CascadeType.ALL)
@JoinTable(
        name = "users_specs",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "spec_id")
)
private Set<SpecEntity> specs;

现在,问题来了。虽然我希望用户实体能够创建新帐户(或联系人)或更新现有帐户(就像现在发生的那样),但我不希望规范发生同样的情况。用户只能添加或删除规范,无权创建新规范或更改规范的属性。

配置这种行为的正确方法是什么?

以下代码显示了我想主要使用配置做什么:

  userEntity.setSpecs(
            userEntity
                    .getSpecs()
                    .stream()
                    .map(spec -> specSvc.get(spec.getId()))
                    .collect(Collectors.toSet())
    );

我正在做的是“纠正”客户端发送的每个规范实体。通过更正,我的意思是防止名称(或任何其他类型的属性)更改,以便用户只能添加或删除规范。但无法更新或创建它们。如果服务器接收到一个不包含 id 的规范,它会抛出一个错误

【问题讨论】:

  • 你的 json 和 JPA 实体有不同的类吗?在几乎每个框架中,都希望为这两个关注点使用不同的类,以便每个关注点都可以独立发展,如您的问题所示。
  • 不,暂时控制器直接接收用户实体对象。您是否建议控制器接收稍后转换为实体的不同类型的对象?
  • 嗨阿莱西奥!下面的塞巴斯蒂安回答是现场的。我建议您阅读有关Model-View-Controller 的信息,以了解这种分离以及为什么它是可取的。对于 API,您可以将 View 作为 JSON 表示(或对象)。我还建议您阅读本书Implementing Domain-Driven Design,因为它对如何设计应用程序进行了深入(并提供大量示例)
  • 感谢您的图书建议。我会明确地把它放在我的愿望清单中。顺便说一句,我对 MVC 并不陌生(我所有的其余 api 都是通过该框架实现的),我完全理解为什么需要分离。如果您知道我的意思,问题是将其转换为基于实体框架的应用程序。但感谢您和塞巴斯蒂安的回答,我正在向前迈进。真的很感谢

标签: java jpa


【解决方案1】:

一般来说,不要让用户直接发布您的实体。无论如何,这将导致未来各种不同的问题。仅在您的示例中,如果用户客户端可以设置数据库 ID,这将是不常见的。如果您让用户更新他们自己的帐户,您可能不希望他们能够设置角色。

我会创建一些 DTO 对象,然后手动映射或使用一些映射器将它们映射到 JPA 实体。

How to properly convert domain entities to DTOs while considering scalability & testability 中有一些不同的方法(尽管这与您的情况大致相反),我在那里链接到我自己的答案,但有多种选择。

【讨论】:

  • 我完全明白你的意思。这只是一个“练习”,我的主要问题是如何管理亲子关系。我将研究 DTO。可能,它们也可能是验证请求正文的好方法(因为我希望控制器而不是存储库来阻止错误的请求)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-29
  • 2021-07-05
  • 2021-12-10
  • 2018-11-27
  • 1970-01-01
相关资源
最近更新 更多