【问题标题】:Assigning a column value instead of an Entity in a JPA @OneToOne mapping在 JPA @OneToOne 映射中分配列值而不是实体
【发布时间】:2021-09-20 17:38:06
【问题描述】:

在我的数据库中,我有 usersrolesclassifications 的表。一个用户只能有一个角色和一个分类。这些表不包含任何外键。相反,我有两个连接表; user_rolesuser_classifications。这些表中的每一行都将user_idrole_idclassification_id 相关联。这是可取的,因为可以将相同的角色/分类分配给多个唯一用户。这样就不需要有多个具有相同角色/分类但具有指向用户的不同外键的行。

rolesclassifications 表比较简单,一个id 列和一个name 列,名称为VARCHAR 类型。我有一个 Spring 应用程序,其中 UserRepository 扩展 JpaRepositoryUser 模型包含 javax.persistence 注释。这里是:

@Entity
@Table(name = "users")
public class User {
    @Id
    private String id;
    
    // ... other fields here
    
    @OneToOne
    @JoinTable(
        name = "user_classifications",
        joinColumns = @JoinColumn(
            name = "user_id",
            referencedColumnName = "id"
        ),
        inverseJoinColumns = @JoinColumn(
            name = "classification_id",
            referencedColumnName = "id"
        ))
    private Classification classification;

    @OneToOne
    @JoinTable(
        name = "user_roles",
        joinColumns = @JoinColumn(
            name = "user_id",
            referencedColumnName = "id"
        ),
        inverseJoinColumns = @JoinColumn(
            name = "role_id",
            referencedColumnName = "id"
        ))
    private Role role;
    
    // ... the rest of the  model
}

@Entity
@Table(name = "roles")
public class Role {
    @Id
    private String id;

    @Column(name = "role_name")
    private String name;
}

@Entity
@Table(name = "classifications")
public class Classification {
    @Id
    private String id;

    @Column(name = "classification_name")
    private String name;
}

最初,roleclassification 字段是 String 类型。 Jpa 不喜欢这样,因为它希望映射到镜像相应表的对象。所以为了让 Jpa 高兴,我为 RoleClassification 创建了额外的 POJO。这很有效,我可以看到从 Jpa 返回的对象,包括 id 和 name 字段。问题是我的前端需要字符串类型。我可以修改前端以“检查”返回的模型并只保留相关的字符串数据(名称)。我不得不想象我在这里遗漏了一些东西,只需从对象中设置字符串值是可能的。在谷歌上搜索答案时,我觉得我问错了问题。我希望通过在这里解释我的情况,我会得到更好的结果。非常感谢您的帮助。

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    这并不能真正回答您的问题,但也可以解决您的问题。 我认为,绝对不建议在您的实体中使用 REST API。您应该根据您的业务案例定义核心模型,因为它更有意义。然后,您应该将基于实体的核心模型映射到 DTO,以最适合使用您的 API 的人的需求的方式组织模型。

    话虽如此,您应该尝试将您的实体与您在 API 中提供的模型分离。这将允许您更改核心模型并保持 API 模型不变。或者反过来。因此,我强烈建议您创建一个适合您的消费者需求的 API 模型,并将您的实体映射到此模型。

    【讨论】:

    • 谢谢,这仍然很有帮助。这是一位同事向我建议的方法之一。
    【解决方案2】:

    按照 João Dias 的建议,您应该使用 DTO,我认为这是 Blaze-Persistence Entity Views 的完美用例。

    我创建了该库以允许在 JPA 模型和自定义接口或抽象类定义模型之间轻松映射,例如 Spring Data Projections on steroids。这个想法是您按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。

    使用 Blaze-Persistence Entity-Views 的用例的 DTO 模型可能如下所示:

    @EntityView(User.class)
    public interface UserDto {
        @IdMapping
        String getId();
        @Mapping("role.name")
        String getRoleName();
        @Mapping("classification.name")
        String getClassificationName();
    }
    

    查询是将实体视图应用于查询的问题,最简单的就是通过 id 进行查询。

    UserDto a = entityViewManager.find(entityManager, UserDto.class, id);

    Spring Data 集成让您可以像使用 Spring Data Projections 一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

    Page<UserDto> findAll(Pageable pageable);
    

    最好的部分是,它只会获取实际需要的状态!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-13
      • 1970-01-01
      相关资源
      最近更新 更多