[英]spring-data-jpa 3-way-intersection table
I'll try to illustrate what I'm trying to achieve shortly... Let's suppose I have a users table:我将尝试说明我很快要实现的目标......假设我有一个用户表:
USER_INFO
USER_ID [PK]
USER_NAME
PASSWORD
an intersection table to define connections for each user (N:M - ManyToMany)为每个用户定义连接的交集表 (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)]
The CONNECTION_TYPE is simple as: CONNECTION_TYPE 很简单:
CONNECTION_TYPE
CONNECTION_TYPE_ID [PK]
CONNECTION_TYPE_NAME [CHECK allowed values are: FRIEND, FAMILY, ...]
On Spring side I defined my User entity as:在 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, ...
}
I have a UserRepository interface that extends JpaRepository etc etc. Now, this works perfectly and I can retrieve all connections be it FRIEND, FAMILY, MOST_HATED_PERSONS, BLOCKED, DEMON, etc...我有一个扩展 JpaRepository 等的 UserRepository 接口。现在,它完美运行,我可以检索所有连接,无论是 FRIEND、FAMILY、MOST_HATED_PERSONS、BLOCKED、DEMON 等...
I tried to integrate the ConnectionType too in the picture however...我也尝试在图片中集成 ConnectionType ......
@Entity
@Table(name = "CONNECTION_TYPE")
public class Connection implements Serializable {
public static enum Types {
FRIEND, FAMILY, BLOCKED, ...
}
@Id
@NotNull
@Column(name = "CONNECTION_TYPE_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer connectionTypeId;
@Column(name = "CONNECTION_TYPE_NAME")
private ConnectionType connectionType;
// ctor, getters, setter, etc
}
Now, my question is, how can I get only specific connections for a given user, based on Connection.Types?现在,我的问题是,如何根据 Connection.Types 仅获取给定用户的特定连接? For example I want to find only FRIENDs, or only FAMILY I think you get my point.
例如,我只想找到 FRIENDs 或 FAMILY,我想你明白我的意思。 This 3 way intersection table gives me one of a headache.
这个 3 路交叉表让我很头疼。
@Clarification: What I want is a @ManyToMany relation defined on my User entity that happen to have extra column. @Clarification:我想要的是在我的用户实体上定义的@ManyToMany 关系,它恰好有额外的列。 I know in that case there are proposed solutions like LINK .
我知道在这种情况下,有建议的解决方案,例如LINK 。 In my case this extra column is a foreign key to a third table (USER_INFO(Holds the users), CONNECTION_INFO(Holds the connections between users N:M + an info on the type of connection), CONNECTION_TYPE. If I can model it with spring-data-jpa from what I understand I only need a magic named method under UserRepository, something like (totally incorrect):
在我的情况下,这个额外的列是第三个表的外键(USER_INFO(保存用户),CONNECTION_INFO(保存用户之间的连接N:M +有关连接类型的信息),CONNECTION_TYPE。如果我可以 model 它与spring-data-jpa 据我了解,我只需要在 UserRepository 下使用一个名为魔法的方法,类似于(完全不正确):
public interface UserRepository extends JpaRepository<User, Integer> {
List<User> findUserFriendsByConnectionType(User userWhoseFriendsWeAreSearching, String connectionTypeFromTheThirdTable);
}
That's all I want.这就是我想要的。 I know it's simple with a normal extra column by creating an entity for the intersection table too and break the ManyToMany to OneToMany and ManyToOne, it just happens I have a third table and a possibly ManyToOne (1 connection can have 1 associated type, while a type can be linked to any number of connections) on the intersection entity with the connection_type table.
我知道通过为交集表创建一个实体并将ManyToMany分解为OneToMany和ManyToOne,使用普通的额外列很简单,只是碰巧我有第三个表和一个可能的ManyToOne(1个连接可以有1个关联类型,而一个type 可以链接到任意数量的连接)在与 connection_type 表的交集实体上。
I hope it clears everything up.我希望它能清除一切。 The above are just a sample I never imagined we'd hang up on an enum because I wanted to make it look simple I possibly made it way too simple perhaps:).
以上只是我从未想过我们会挂在枚举上的示例,因为我想让它看起来简单,我可能让它太简单了:)。
I managed to solve the problem but I'm not sure if this is the right way to do it.我设法解决了这个问题,但我不确定这是否是正确的方法。 Anyway here's my solution.
无论如何,这是我的解决方案。 Consider the following 3 tables:
考虑以下 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)
With the above 3 tables, I want to provide a functionality to get connections for any given user based on the connection's type.对于上面的 3 个表,我想提供一个功能来根据连接的类型为任何给定的用户获取连接。 For this I created 3 entities as follows:
为此,我创建了 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;
...
}
Nothing particularly interesting in here, I omitted the constructor, getters, setters etc and from the ConnectionType I don't want to have a mapping for all connections for this type so that direction is not present.这里没有什么特别有趣的,我省略了构造函数、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;
...
}
This one is more interesting if for noone else at least for me.如果没有其他人至少对我来说,这个更有趣。 This would be my intersection table entity.
这将是我的交集表实体。 There's the uni-directional mapping for the used ConnectionType with ManyToOne as one Connection can have exactly one ConnectionType while the same ConnectionType can be reused for an arbitrary number of Connections.
使用的 ConnectionType 与 ManyToOne 存在单向映射,因为一个 Connection 可以只有一个 ConnectionType,而相同的 ConnectionType 可以用于任意数量的 Connection。 The other 2 User mappings I'm sure I've messed up but before that here's the User entity:
其他 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;
}
Now here I'm even more sure I completely messed up, but I'll show the actual error.现在在这里我更加确定我完全搞砸了,但我会显示实际的错误。 My repository is simple as a brick:
我的存储库很简单:
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
}
And I have a UserService with a simplified findAllConnectionsForUserById function:我有一个带有简化 findAllConnectionsForUserById function 的 UserService:
@Service
public interface UserService {
List<User> findAllConnectionsForUserById(Integer userId);
}
The method implementation is simple enough:方法实现很简单:
@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());
This way it seem to work fine for the simple case and in case I take the ConnectionType too:这种方式似乎适用于简单的情况,如果我也采用 ConnectionType:
connections.stream().filter(c -> c.getConnectionType().getConnectionTypeName().equals("FRIEND")).map(Connection::getRelatingUser).collect(Collectors.toList());
it seem to work as well.它似乎也有效。 Again, not sure if this is the right way but at least it does the job.
同样,不确定这是否是正确的方法,但至少它可以完成工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.