![](/img/trans.png)
[英]What is the right way to create custom query in spring-data-jpa
[英]spring-data-jpa 3-way-intersection table
我將嘗試說明我很快要實現的目標......假設我有一個用戶表:
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 方面,我將我的用戶實體定義為:
@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, ...
}
我有一個擴展 JpaRepository 等的 UserRepository 接口。現在,它完美運行,我可以檢索所有連接,無論是 FRIEND、FAMILY、MOST_HATED_PERSONS、BLOCKED、DEMON 等...
我也嘗試在圖片中集成 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
}
現在,我的問題是,如何根據 Connection.Types 僅獲取給定用戶的特定連接? 例如,我只想找到 FRIENDs 或 FAMILY,我想你明白我的意思。 這個 3 路交叉表讓我很頭疼。
@Clarification:我想要的是在我的用戶實體上定義的@ManyToMany 關系,它恰好有額外的列。 我知道在這種情況下,有建議的解決方案,例如LINK 。 在我的情況下,這個額外的列是第三個表的外鍵(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);
}
這就是我想要的。 我知道通過為交集表創建一個實體並將ManyToMany分解為OneToMany和ManyToOne,使用普通的額外列很簡單,只是碰巧我有第三個表和一個可能的ManyToOne(1個連接可以有1個關聯類型,而一個type 可以鏈接到任意數量的連接)在與 connection_type 表的交集實體上。
我希望它能清除一切。 以上只是我從未想過我們會掛在枚舉上的示例,因為我想讓它看起來簡單,我可能讓它太簡單了:)。
我設法解決了這個問題,但我不確定這是否是正確的方法。 無論如何,這是我的解決方案。 考慮以下 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 與 ManyToOne 存在單向映射,因為一個 Connection 可以只有一個 ConnectionType,而相同的 ConnectionType 可以用於任意數量的 Connection。 其他 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;
}
現在在這里我更加確定我完全搞砸了,但我會顯示實際的錯誤。 我的存儲庫很簡單:
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
}
我有一個帶有簡化 findAllConnectionsForUserById function 的 UserService:
@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());
這種方式似乎適用於簡單的情況,如果我也采用 ConnectionType:
connections.stream().filter(c -> c.getConnectionType().getConnectionTypeName().equals("FRIEND")).map(Connection::getRelatingUser).collect(Collectors.toList());
它似乎也有效。 同樣,不確定這是否是正確的方法,但至少它可以完成工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.