【问题标题】:Adding associated entities in Spring Data JPA在 Spring Data JPA 中添加关联实体
【发布时间】:2016-04-11 18:59:54
【问题描述】:

我有一个 JPA 实体 Person 和一个实体 Team。从逻辑上讲,Person 和 Team 具有 ManyToMany 关系。但是因为我有一个附加属性,即团队中人员的角色,它限定了关系,我必须将关系建模为与联合实体的两个关系,我称之为PersonToTeam。代码如下:

public class Person {
    @Id
    private String id;
    private String name;
    @OneToMany(mappedBy = "id.person", cascade = { CascadeType.ALL })
    private List<PersonToTeam> teamAssociations = new ArrayList<>();
}

public class Team {
    @Id
    private String id;
    private String name;
    @OneToMany(mappedBy = "id.team", cascade = { CascadeType.ALL })
    private List<PersonToTeam> teamAssociations = new ArrayList<>();
}

public class PersonToTeam {
    @EmbeddedId
    private PersonToTeamId id = new PersonToTeamId();
    private RoleInTeam role;

    public enum RoleInTeam {
        ADMIN, MEMBER
    }
}

public class PersonToTeamId implements Serializable {
    private static final long serialVersionUID = -8450195271351341722L;
    @ManyToOne
    private Person person;
    @ManyToOne
    private Team team;
}

到目前为止一切顺利。但我不喜欢将管理员添加到团队中的努力。这看起来像:

Person person = new Person();
person.setId("d022051");
person.setName("Gregor Frey");
personRepo.save(person);

Team team = new Team();
team.setId("SpringTutorial");
team.setName("Spring Tutorial");

PersonToTeam assoc = new PersonToTeam();
assoc.getId().setPerson(person);
assoc.getId().setTeam(team);
assoc.setRole(RoleInTeam.ADMIN);

List<PersonToTeam> teamAssociations = person.getTeamAssociations();
teamAssociations.add(assoc);
List<PersonToTeam> personAssociations = team.getTeamAssociations();
personAssociations.add(assoc);

teamRepo.save(team);

我想要一个方法 addAdminToTeam,它接受一个人,创建一个新的 personToTeam 关​​联并将其添加到团队中的关联人员集合中。

我的问题是:我应该把这个方法放在哪里?在实体中,作为临时设置者?在存储库中(这可能吗)?还是在单独的服务对象中?还有其他方法可以简化程序吗?

【问题讨论】:

  • 您的问题更多是关于基本封装而不是 JPA。为了确保数据模型在任何单个时间点的正确性,将操作封装在实体中并返回关联的迭代器/不可修改的集合,以便强制客户端类通过这些方法。客户端代码将永远无法使模型处于不一致的状态,即通过设置关系的一侧而不设置另一侧。

标签: spring jpa spring-data spring-data-jpa


【解决方案1】:

在我的建议中,您应该创建一个存储库层,您可以在其中放置所有“存储库”逻辑。在这一层中,您应该放置所有 CRUD 方法 (DAO) 以及您想要与您的实体和实体间相关的所有其他方法,例如 DCS(数据控制服务模式)。

通过这种方式,您可以拥有一个单一的存储库责任类,而无需在服务层中分散您的数据库逻辑。

这应该被视为架构样式的建议,这是一个有效的选择,因为在您的代码段中只有存在逻辑而不是业务逻辑。

如果您的 addAdminToTeam 方法必须执行更多工作然后影响您的业务逻辑,音乐就会发生变化。对于安全日志等,您可以依赖 Spring AOP,但对于其他承诺,您应该考虑服务层。但是,在您的情况下,我认为上述存储库层是最佳解决方案。在我看来,setter 选项不是一个好的选择,因为您在域对象中创建了持久性事物的紧密耦合实现,并且对于将逻辑分散在 java 代码和在数据库中运行的代码的过程.

希望对你有帮助

【讨论】:

  • 感谢您的建议。我倾向于同意将数据访问逻辑放在存储库中,并使持久层不受数据模型之外的任何东西的影响。但我想知道,我是否可以将 addPersonAsAdmin 之类的方法作为 JPARepository= 添加到团队存储库中
  • 是的,这是可能的。对于在您的存储库中添加自定义方法,存在链接文档中描述的策略:docs.spring.io/spring-data/jpa/docs/1.10.1.RELEASE/reference/… 第 4.6 章,我在我的开源项目中使用它,您可以在链接上查看详细信息:github.com/mrFlick72/socialDocumentLibrary/tree/master/…。对于更新查询,您的方法应使用第 5.3.7 章中描述的@Modifying 注释
  • 这种方法的缺点是,Spring Data Rest 没有考虑到这样的自定义方法。如果我将管理员建模为团队的临时属性,Spring Data Rest 会将管理员显示为团队的子资源。
  • 好的,但我不知道您的重点是 Spring Data Rest,因为这篇文章是针对 Spring Data 的。
  • 是的,当然。这只是为了传达问题的上下文。你的回答非常有效。我喜欢清晰的关注点分离。只是自定义存储库扩展从其他角度来看并没有无缝集成。
猜你喜欢
  • 1970-01-01
  • 2014-09-22
  • 1970-01-01
  • 2014-06-21
  • 2021-05-22
  • 2015-09-11
  • 1970-01-01
  • 2019-12-01
  • 2015-08-31
相关资源
最近更新 更多