Java spring数据jpa三向交叉表
我将试图说明我很快将要实现的目标。。。 假设我有一个用户表:Java spring数据jpa三向交叉表,java,spring-boot,java-8,spring-data-jpa,Java,Spring Boot,Java 8,Spring Data Jpa,我将试图说明我很快将要实现的目标。。。 假设我有一个用户表: USER_INFO USER_ID [PK] USER_NAME PASSWORD 为每个用户定义连接的交集表(N:M-manytoman) 连接类型很简单,如下所示: CONNECTION_TYPE CONNECTION_TYPE_ID [PK] CONNECTION_TYPE_NAME [CHECK allowed values are: FRIEND, FAMILY, ...] 在Spring端,我将我的
USER_INFO
USER_ID [PK]
USER_NAME
PASSWORD
为每个用户定义连接的交集表(N:M-manytoman)
连接类型很简单,如下所示:
CONNECTION_TYPE
CONNECTION_TYPE_ID [PK]
CONNECTION_TYPE_NAME [CHECK allowed values are: FRIEND, FAMILY, ...]
在Spring端,我将我的用户实体定义为:
@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, ...
}
现在,我的问题是,如何根据Connection.Types仅获取给定用户的特定连接?例如,我只想找朋友,或者只想找家人,我想你明白我的意思了。这张三向交叉表让我头疼
@澄清:
我想要的是在我的用户实体上定义的一个@ManyToMany关系,它恰好有额外的列。我知道在这种情况下,会有类似的解决方案。在我的例子中,这个额外的列是第三个表(USER_INFO(保存用户)、CONNECTION_INFO(保存用户之间的连接N:M+关于连接类型的信息)、CONNECTION_type)的外键(完全不正确):
public interface UserRepository扩展了JpaRepository{
按连接类型列出FindUserFriends(正在搜索好友的用户,第三个表中的字符串连接类型);
}
这就是我想要的。我知道,通过为交集表创建一个实体并打破多对一多和多对一,使用一个普通的额外列很简单,碰巧我有第三个表和一个可能的多对一(1个连接可以有1个关联类型,而一个类型可以链接到任意数量的连接)在具有连接类型表的相交图元上
我希望它能把一切都清理干净。以上只是我从未想象过的一个样本,因为我想让它看起来简单,也许我把它做得太简单了。)。我设法解决了这个问题,但我不确定这是不是正确的方法。总之,我的解决方案。考虑下面3个表:
create table USER_INFO (
USER_ID int not null primary key,
USER_NAME varchar(16),
PASSWORD varchar(64)
);
create table CONNECTION_TYPE (
CONNECTION_TYPE_ID int not null primary key,
CONNECTION_TYPE_NAME varchar(16) not null,
CONNECTION_TYPE_DESCRIPTION varchar(128),
unique (CONNECTION_TYPE_NAME)
);
create table CONNECTION (
CONNECTION_ID int not null primary key,
CONNECTION_TYPE_ID int,
RELATED_USER_ID int,
RELATING_USER_ID int,
foreign key (CONNECTION_TYPE_ID) references CONNECTION_TYPE(CONNECTION_TYPE_ID),
foreign key (RELATED_USER_ID) references USER_INFO(USER_ID),
foreign key (RELATING_USER_ID) references USER_INFO(USER_ID)
通过以上3个表,我想提供一个功能,根据连接类型为任何给定用户获取连接。为此,我创建了3个实体,如下所示:
@Entity
@Table(name = "CONNECTION_TYPE")
public class ConnectionType implements Serializable {
@Id
@NotNull
@Column(name = "CONNECTION_TYPE_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer connectionTypeId;
@NotNull
@Column(name = "CONNECTION_TYPE_NAME", unique = true)
private String connectionTypeName;
@Column(name = "CONNECTION_TYPE_DESCRIPTION")
private String connectionTypeDescription;
...
}
这里没有什么特别有趣的,我省略了构造函数、getter、setter等,从ConnectionType中,我不想为这个类型的所有连接都有一个映射,这样就没有方向了
@Entity
@Table(name = "CONNECTION")
public class Connection implements Serializable {
@Id
@NotNull
@Column(name = "CONNECTION_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer connectionId;
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CONNECTION_TYPE_ID", referencedColumnName = "CONNECTION_TYPE_ID")
private ConnectionType connectionType;
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "RELATED_USER_ID", referencedColumnName = "USER_ID")
private User relatedUser;
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "RELATING_USER_ID", referencedColumnName = "USER_ID")
private User relatingUser;
...
}
如果没有其他人,至少对我来说,这个更有趣。这将是我的交集表实体。使用的ConnectionType具有单向映射,其中包含多个Connection,因为一个连接可以有一个ConnectionType,而相同的ConnectionType可以重复用于任意数量的连接。
其他2个用户映射我肯定搞糟了,但在此之前,这里是用户实体:
@Entity
@Table(name = "USER_INFO")
public class User implements Serializable {
@Id
@NotNull
@Column(name = "USER_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer userId;
@NotNull
@Column(name = "USER_NAME")
private String userName;
@NotNull
@Column(name = "PASSWORD")
private char[] password;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "relatedUser", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Connection> connections;
}
这似乎也起作用。同样,不确定这是不是正确的方法,但至少它能起作用。 < P>我设法解决了这个问题,但我不确定这是不是正确的方法。总之,这是我的解决方案。考虑下面3个表:
create table USER_INFO (
USER_ID int not null primary key,
USER_NAME varchar(16),
PASSWORD varchar(64)
);
create table CONNECTION_TYPE (
CONNECTION_TYPE_ID int not null primary key,
CONNECTION_TYPE_NAME varchar(16) not null,
CONNECTION_TYPE_DESCRIPTION varchar(128),
unique (CONNECTION_TYPE_NAME)
);
create table CONNECTION (
CONNECTION_ID int not null primary key,
CONNECTION_TYPE_ID int,
RELATED_USER_ID int,
RELATING_USER_ID int,
foreign key (CONNECTION_TYPE_ID) references CONNECTION_TYPE(CONNECTION_TYPE_ID),
foreign key (RELATED_USER_ID) references USER_INFO(USER_ID),
foreign key (RELATING_USER_ID) references USER_INFO(USER_ID)
通过以上3个表,我想提供一个功能,根据连接类型为任何给定用户获取连接。为此,我创建了3个实体,如下所示:
@Entity
@Table(name = "CONNECTION_TYPE")
public class ConnectionType implements Serializable {
@Id
@NotNull
@Column(name = "CONNECTION_TYPE_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer connectionTypeId;
@NotNull
@Column(name = "CONNECTION_TYPE_NAME", unique = true)
private String connectionTypeName;
@Column(name = "CONNECTION_TYPE_DESCRIPTION")
private String connectionTypeDescription;
...
}
这里没有什么特别有趣的,我省略了构造函数、getter、setter等,从ConnectionType中,我不想为这个类型的所有连接都有一个映射,这样就没有方向了
@Entity
@Table(name = "CONNECTION")
public class Connection implements Serializable {
@Id
@NotNull
@Column(name = "CONNECTION_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer connectionId;
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CONNECTION_TYPE_ID", referencedColumnName = "CONNECTION_TYPE_ID")
private ConnectionType connectionType;
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "RELATED_USER_ID", referencedColumnName = "USER_ID")
private User relatedUser;
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "RELATING_USER_ID", referencedColumnName = "USER_ID")
private User relatingUser;
...
}
如果没有其他人,至少对我来说,这个更有趣。这将是我的交集表实体。使用的ConnectionType具有单向映射,其中包含多个Connection,因为一个连接可以有一个ConnectionType,而相同的ConnectionType可以重复用于任意数量的连接。
其他2个用户映射我肯定搞糟了,但在此之前,这里是用户实体:
@Entity
@Table(name = "USER_INFO")
public class User implements Serializable {
@Id
@NotNull
@Column(name = "USER_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer userId;
@NotNull
@Column(name = "USER_NAME")
private String userName;
@NotNull
@Column(name = "PASSWORD")
private char[] password;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "relatedUser", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Connection> connections;
}
它似乎也能工作。同样,不确定这是否是正确的方法,但至少它能完成任务。如果它只有固定值,为什么还要添加表?它不是枚举,而是实体。因此,您应该有一个实体,而不是枚举
连接类型。您当前的设置将失败,因为连接信息table没有这两列。哇,很好的捕捉…我完全搞砸了命名…我希望我现在能正确地清理它。我没有交集表的实体:)。在第一点上,这里的附加表i必须能够定义新的连接类型。您不能只定义新的连接类型,因为您已经在java代码的枚举中硬编码了它们。因此,它还需要更改代码。如果要将一个实体映射到多个表,则您的连接
应具有@Table
和[@SecondaryTable
])()表注释。您的
User`应该有一个连接
实体列表,而不是用户
实体列表。然后您可以为特定类型编写查询。这只是一个示例。。。基本上,我想要的是一个多个关系,其中有一个额外的列,恰好是第三个表的外键。然后,在存储库中,我想定义一个函数,比如:findUserConnectionsByConnectionTypeConnectionTypeName,或者类似的函数,如果我正确获取书籍,它会由spring boot自动生成。我不知道你链接我的第二个表是什么,但我90%确定我不需要它。你有3个表和2个实体。因此,您必须添加一个实体,或者为要映射到2个表的1个实体添加额外的映射(@SecondaryTable
注释)。只需为用户
实体中的用户列表添加一个@manytomy
,该实体将不会执行此任务。这必须是一个连接
的列表,它要么有一个连接类型
实体链接,要么是两个表的集合。如果它只有一个
@Service
public interface UserService {
List<User> findAllConnectionsForUserById(Integer userId);
}
@Override
@Transactional
public List<User> findAllConnectionsForUserById(Integer userId) {
Optional<User> _user = userRepository.findById(userId);
// omitted exception handling...
User user = _user.get();
List<Connection> connections = user.getConnections();
return connections.strea.map(Connection::getRelatingUser).collect(Collectors.toList());
connections.stream().filter(c -> c.getConnectionType().getConnectionTypeName().equals("FRIEND")).map(Connection::getRelatingUser).collect(Collectors.toList());