猿问

spring-data-jpa 3路交叉表

我将尝试说明我想尽快实现的目标...假设我有一个用户表:


USER_INFO

  USER_ID [PK]

  USER_NAME

  PASSWORD

用于定义每个用户连接的交集表(N:M - ManyToMany)


CONNECTION_INFO

  CONNECTION_ID [PK]

  USER_A_ID [FK - references USER_INFO(USER_ID)]

  USER_B_ID [FK - references USER_INFO(USER_ID)]

  CONNECTION_TYPE_ID [FK - references CONNECTION_TYPE(CONNECTION_TYPE_ID)]

CONNECTION_TYPE 很简单:


CONNECTION_TYPE

  CONNECTION_TYPE_ID [PK]

  CONNECTION_TYPE_NAME [CHECK allowed values are: FRIEND, FAMILY, ...]

在 Spring 方面,我将我的 User 实体定义为:


@Entity

@Table(name = "USER_INFO")

public class User implements Serializable {

  @Id

  @NotNull

  @Column(name = "USER_ID")

  @GeneratedValue(strategy = GenerationType.IDENTITY)

  private Integer userId;


  @Column(name = "USER_NAME)

  private String userName;


  @Column(name = "PASSWORD)

  private char[] password;


  @ManyToMany(fetch = FetchType.LAZY)

  @JoinTable(name = "CONNECTION_INFO",

             joinColumns = { @JoinColumn(name = "USER_A_ID") },

             inverseJoinColumns = { @JoinColumn(name = "USER_B_ID") })

  private List<User> connections;


  // ctor, getters, setters, toString, ...

}

我有一个 UserRepository 接口,它扩展了 JpaRepository 等。现在,它工作得很好,我可以检索所有连接,无论是朋友、家人、最讨厌的人、被阻止、恶魔等...


现在,我的问题是,如何根据 Connection.Types 只获取给定用户的特定连接?例如,我只想找到朋友,或者只想找到家人,我想你明白我的意思。这个三路交叉表让我很头疼。


@Clarification:我想要的是在我的用户实体上定义的 @ManyToMany 关系,该实体恰好有额外的列。我知道在这种情况下有建议的解决方案,例如LINK。在我的例子中,这个额外的列是第三个表的外键(USER_INFO(保存用户),CONNECTION_INFO(保存用户之间的连接N:M +有关连接类型的信息),CONNECTION_TYPE。如果我可以用它来建模spring-data-jpa 据我了解,我只需要 UserRepository 下的一个神奇的命名方法,类似于(完全不正确):


public interface UserRepository extends JpaRepository<User, Integer> {

    List<User> findUserFriendsByConnectionType(User userWhoseFriendsWeAreSearching, String connectionTypeFromTheThirdTable);

}

这就是我想要的。我知道通过为交叉表创建一个实体并打破ManyToMany到OneToMany和ManyToOne,使用普通的额外列很简单,碰巧我有第三个表和可能的ManyToOne(1个连接可以有1个关联类型,而一个连接可以有1个关联类型) type 可以链接到任意数量的连接)与 connection_type 表的交集实体上。


我希望它能澄清一切。上面只是一个示例,我从未想过我们会挂在枚举上,因为我想让它看起来简单,我可能让它变得太简单了:)。


犯罪嫌疑人X
浏览 86回答 1
1回答

慕工程0101907

我设法解决了这个问题,但我不确定这是否是正确的方法。无论如何,这是我的解决方案。考虑以下 3 个表:create table USER_INFO (&nbsp; USER_ID int not null primary key,&nbsp; USER_NAME varchar(16),&nbsp; PASSWORD varchar(64));create table CONNECTION_TYPE (&nbsp; CONNECTION_TYPE_ID int not null primary key,&nbsp; CONNECTION_TYPE_NAME varchar(16) not null,&nbsp; CONNECTION_TYPE_DESCRIPTION varchar(128),&nbsp; unique (CONNECTION_TYPE_NAME));create table CONNECTION (&nbsp; CONNECTION_ID int not null primary key,&nbsp; CONNECTION_TYPE_ID int,&nbsp; RELATED_USER_ID int,&nbsp; RELATING_USER_ID int,&nbsp; foreign key (CONNECTION_TYPE_ID) references CONNECTION_TYPE(CONNECTION_TYPE_ID),&nbsp; foreign key (RELATED_USER_ID) references USER_INFO(USER_ID),&nbsp; foreign key (RELATING_USER_ID) references USER_INFO(USER_ID)通过上述 3 个表,我想提供一种功能来根据连接类型获取任何给定用户的连接。为此,我创建了 3 个实体,如下所示:@Entity@Table(name = "CONNECTION_TYPE")public class ConnectionType implements Serializable {&nbsp; @Id&nbsp; @NotNull&nbsp; @Column(name = "CONNECTION_TYPE_ID")&nbsp; @GeneratedValue(strategy = GenerationType.IDENTITY)&nbsp; private Integer connectionTypeId;&nbsp; @NotNull&nbsp; @Column(name = "CONNECTION_TYPE_NAME", unique = true)&nbsp; private String connectionTypeName;&nbsp; @Column(name = "CONNECTION_TYPE_DESCRIPTION")&nbsp; private String connectionTypeDescription;&nbsp; ...}这里没有什么特别有趣的地方,我省略了构造函数、getter、setter 等,并且从 ConnectionType 中我不想为该类型的所有连接提供映射,因此不存在方向。@Entity@Table(name = "CONNECTION")public class Connection implements Serializable {&nbsp; @Id&nbsp; @NotNull&nbsp; @Column(name = "CONNECTION_ID")&nbsp; @GeneratedValue(strategy = GenerationType.IDENTITY)&nbsp; private Integer connectionId;&nbsp; @NotNull&nbsp; @ManyToOne(fetch = FetchType.LAZY)&nbsp; @JoinColumn(name = "CONNECTION_TYPE_ID", referencedColumnName = "CONNECTION_TYPE_ID")&nbsp; private ConnectionType connectionType;&nbsp; @NotNull&nbsp; @ManyToOne(fetch = FetchType.LAZY)&nbsp; @JoinColumn(name = "RELATED_USER_ID", referencedColumnName = "USER_ID")&nbsp; private User relatedUser;&nbsp; @NotNull&nbsp; @ManyToOne(fetch = FetchType.LAZY)&nbsp; @JoinColumn(name = "RELATING_USER_ID", referencedColumnName = "USER_ID")&nbsp; private User relatingUser;&nbsp; ...}如果对其他人来说,至少对我而言,这更有趣。这将是我的交集表实体。对于使用的 ConnectionType 与 ManyToOne 存在单向映射,因为一个 Connection 只能具有一个 ConnectionType,而同一 ConnectionType 可以重复用于任意数量的 Connection。其他 2 个用户映射我确信我已经搞砸了,但在此之前这是用户实体:@Entity@Table(name = "USER_INFO")public class User implements Serializable {&nbsp; @Id&nbsp; @NotNull&nbsp; @Column(name = "USER_ID")&nbsp; @GeneratedValue(strategy = GenerationType.IDENTITY)&nbsp; private Integer userId;&nbsp; @NotNull&nbsp; @Column(name = "USER_NAME")&nbsp; private String userName;&nbsp; @NotNull&nbsp; @Column(name = "PASSWORD")&nbsp; private char[] password;&nbsp; @OneToMany(fetch = FetchType.LAZY, mappedBy = "relatedUser", cascade = CascadeType.ALL, orphanRemoval = true)&nbsp; private List<Connection> connections;}现在我更加确定我完全搞砸了,但我会显示实际的错误。我的存储库很简单:@Repositorypublic interface UserRepository extends JpaRepository<User, Integer> {}我有一个带有简化的 findAllConnectionsForUserById 函数的 UserService :@Servicepublic interface UserService {&nbsp; &nbsp; List<User> findAllConnectionsForUserById(Integer userId);}该方法的实现非常简单:@Override@Transactionalpublic List<User> findAllConnectionsForUserById(Integer userId) {&nbsp; &nbsp; Optional<User> _user = userRepository.findById(userId);&nbsp; &nbsp; // omitted exception handling...&nbsp; &nbsp; User user = _user.get();&nbsp; &nbsp; List<Connection> connections = user.getConnections();&nbsp; &nbsp; return connections.strea.map(Connection::getRelatingUser).collect(Collectors.toList());这样,对于简单的情况,它似乎工作得很好,并且如果我也采用 ConnectionType:connections.stream().filter(c -> c.getConnectionType().getConnectionTypeName().equals("FRIEND")).map(Connection::getRelatingUser).collect(Collectors.toList());它似乎也有效。同样,不确定这是否是正确的方法,但至少它可以完成工作。
随时随地看视频慕课网APP

相关分类

Java
我要回答