我的情况如下
用户可以具有一个跟踪列表,与之相对应,跟踪实体包含一个用户ID。({{1} })
每创建一个新曲目,曲目列表就会更新。
上述实体如下:
跟踪实体
@OneToMany
用户实体
@Entity
@Table(name ="track")
public class Track {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long trackId;
@ManyToOne
@JoinColumn(name = "userId", nullable = false)
private User user;
@OneToOne(mappedBy = "track")
private Share share;
private String trackName;
@OneToMany(mappedBy = "pointId")
private List<Point> point;
@OneToOne(mappedBy = "track")
private TrackStatistic trackStatistic;
@Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name = "USER_ID") private Long id; private String firstName; private String lastName; @Column(unique = true) private String username; private String password; @Column(unique = true) private String email; @Column(unique = true) private String phoneNumber; private int age; private Role role; @OneToMany(mappedBy = "shareId") private List<Share> shares; @OneToMany(mappedBy = "trackId") private List<Track> tracks; }
方法如下
createTrack
请注意,public Track createTrack(String username, TrackDTO trackDTO) {
//Find user
User user = userRepository.findByUsername(username);
//Convert Dto to Entity
Track track = modelMapper.map(trackDTO, Track.class);
//Update user track list
user.getTracks().add(track);
//Update track
track.setUser(user);
//save user
userRepository.save(user);
//save track
return trackRepository.save(track);
}
是Track实体的相应Dto类
我运行TrackDTO
时遇到以下错误:
createTrack
答案 0 :(得分:1)
已编辑
通过有效的级联,当您保存User
时,无需再次保存Track
。因此我对您的代码进行了如下更改,希望对您有所帮助
1-将
cascade = CascadeType.ALL
添加到用户实体2-将
targetEntity = Track .class, mappedBy = "user"
添加到用户实体3-将
@ManyToOne(targetEntity = User.class) @JoinColumn(name = "USER_FK")
添加到跟踪实体4-删除
trackRepository.save(track);
5-只需保存用户(
userRepository.save(user)
)。通过级联,它也可以保存轨道。6-返回用户列表中的最后一个曲目。(最新保存的曲目)
我对上述修改进行了编码
用户实体
@Entity
@Table(name = "user")
public class User {
//other properties
@OneToMany(targetEntity = Track.class , mappedBy = "user" ,cascade = CascadeType.ALL)
private List<Track> tracks;
//getters and setters
}
跟踪实体
@Entity
@Table(name ="track")
public class Track {
//other properties
@ManyToOne(targetEntity = User.class)
@JoinColumn(name = "USER_FK",nullable = false)
private User user;
//getters and setters
}
createTrack方法
public Track createTrack(String username, TrackDTO trackDTO) {
//Find user
User user = userRepository.findByUsername(username);
//Convert Dto to Entity
Track track = modelMapper.map(trackDTO, Track.class);
//Update User and Track
user.getTracks().add(track);
track.setUser(user);
//save user
User result = userRepository.save(user);
//find saved track (you can fetch track by other ways too)
Track savedTrack = result.getTracks().get(result.getTracks().size()-1);
return savedTrack;
}
答案 1 :(得分:0)
这种关系是循环的,用户包含轨道,轨道包含用户。双向都有fk约束,所以这个问题。您可以通过保持用户独立性(不涉及跟踪)并保持跟踪引用用户来解决此问题。还有其他解决关系的方法,要删除的要点是避免循环关系
答案 2 :(得分:0)
您应该将曲目保存在用户之前。
// Create XML document
xml_document<> doc;
xml_node<> * root_node;
// Read the xml file into a vector
ifstream theFile (fqn_file);
vector<char> buffer((istreambuf_iterator<char>(theFile)), istreambuf_iterator<char>());
buffer.push_back('\0');
// Parse the buffer using the xml file parsing library into doc
doc.parse<0>(&buffer[0]);
// Find root node
root_node = doc.first_node("ActionMaps");
// Iterate over 'ActionMaps' subtree
for (xml_node<> * actionmap_node = root_node->first_node("actionmap"); actionmap_node; actionmap_node = actionmap_node->next_sibling())
{
wxLogMessage("I found name subsection %s ",
actionmap_node->first_attribute("name")->value());
// Iterate over 'action' subtree
for(xml_node<> * action_node = actionmap_node->first_node("action"); action_node; action_node = action_node->next_sibling())
{
wxLogMessage("I found action name %s ",
action_node->first_attribute("name")->value());
// Iterate over 'rebind' subtree
for(xml_node<> * rebind_node = action_node->first_node("rebind"); rebind_node; rebind_node = rebind_node->next_sibling())
{
wxLogMessage("I found key %s ",
rebind_node->first_attribute("input")->value());
}
}
}
如果是普通的旧SQL查询,您的代码将出错:
20:19:17: I found name subsection spaceship_general
20:19:17: I found action name v_toggle_all_doorlocks
20:19:17: I found key kb1_lshift+l
20:19:17: I found name subsection spaceship_view
20:19:17: I found action name v_view_dynamic_focus
20:19:17: I found key js1_slider1
20:19:17: I found action name v_view_look_behind
20:19:17: I found key js1_button8
20:19:17: I found name subsection spaceship_movement
20:19:17: I found action name v_accel_range_rel
20:19:17: I found key js1_rotx
20:19:17: I found action name v_afterburner
20:19:17: I found key js1_button30
20:19:17: I found action name v_autoland
20:19:17: I found key js1_button14
20:19:17: I found action name v_brake
20:19:17: I found key js1_button7
20:19:17: I found action name v_ifcs_toggle_cruise_control
20:19:17: I found key js1_button12
20:19:17: I found action name v_ifcs_toggle_esp
20:19:17: I found key js1_button11
20:19:17: I found action name v_ifcs_toggle_gforce_safety
20:19:17: I found key js1_button10
20:19:17: I found action name v_ifcs_toggle_speed_limiter
20:19:17: I found key js1_button9
20:19:17: I found action name v_ifcs_toggle_vector_decoupling
20:19:17: I found key js1_button6
20:19:17: I found action name v_roll
20:19:17: I found key js1_x
20:19:17: I found action name v_speed_range_rel
20:19:17: I found key js1_roty
20:19:17: I found action name v_strafe_back
20:19:17: I found key js1_
20:19:17: I found action name v_strafe_down
20:19:17: I found key js1_button22
20:19:17: I found action name v_strafe_forward
20:19:17: I found key js1_
20:19:17: I found action name v_strafe_left
20:19:17: I found key js1_button23
20:19:17: I found action name v_strafe_longitudinal
20:19:17: I found key js1_z
20:19:17: I found action name v_strafe_right
20:19:17: I found key js1_button21
20:19:17: I found action name v_strafe_up
20:19:17: I found key js1_button20
20:19:17: I found action name v_target_match_vel
20:19:17: I found key js1_button28
20:19:17: I found action name v_toggle_landing_system
20:19:17: I found key js1_button13
20:19:17: I found action name v_toggle_vtol
20:19:17: I found key js1_button14
20:19:17: I found action name v_yaw
20:19:17: I found key js1_rotz
20:19:17: I found name subsection spaceship_targeting
20:19:17: I found action name v_target_cycle_all_back
20:19:17: I found key js1_hat1_down
20:19:17: I found action name v_target_cycle_all_fwd
20:19:17: I found key js1_hat1_up
20:19:17: I found action name v_target_cycle_friendly_back
20:19:17: I found key js1_button19
20:19:17: I found action name v_target_cycle_friendly_fwd
20:19:17: I found key js1_button17
20:19:17: I found action name v_target_cycle_hostile_back
20:19:17: I found key js1_hat1_left
20:19:17: I found action name v_target_cycle_hostile_fwd
20:19:17: I found key js1_hat1_right
20:19:17: I found action name v_target_cycle_subitem_back
20:19:17: I found key js1_button18
20:19:17: I found action name v_target_cycle_subitem_fwd
20:19:17: I found key js1_button16
20:19:17: I found name subsection spaceship_weapons
20:19:17: I found action name v_attack1_group2
20:19:17: I found key js1_button5
20:19:17: I found name subsection spaceship_missiles
20:19:17: I found action name v_weapon_arm_missile
20:19:17: I found key js1_button2
20:19:17: I found action name v_weapon_launch_missile
20:19:17: I found key js1_button2
20:19:17: I found name subsection spaceship_defensive
20:19:17: I found action name v_weapon_cycle_countermeasure_fwd
20:19:17: I found key js1_button3
20:19:17: I found action name v_weapon_launch_countermeasure
20:19:17: I found key js1_button4
,但是在保存用户时,public Track createTrack(String username, TrackDTO trackDTO) {
User user = userRepository.findByUsername(username);
Track track = modelMapper.map(trackDTO, Track.class);
user.getTracks().add(track);
track.setUser(user);
userRepository.save(user); // 1
return trackRepository.save(track); // 2
}
尚未保存,因此由于缺少ID,因此您无法分配给用户/跟踪关系。insert into USER_TRACK (<USER>, <TRACK>)
并生成一个id,但之后会发生。您可能会缺少一些JPA映射,因为我认为JPA通常会为您解决这个问题。
答案 3 :(得分:0)
重构实体之间的关系,问题仍然存在。作为轨道和用户之间关系的一个小预览,如下所示: 跟踪实体
import SceneKit
class Cube : SCNNode {
let cubeWidth:Float = 0.95
let spaceBetweenCubes:Float = 0.05
var cubecolor:UIColor = UIColor.black
var masterCubeDict: [SCNNode: CubeDetails] = [:]
struct CubeDetails {
var color:String
var position:SCNVector3
}
override init() {
super.init()
let cubeOffsetDistance = self.cubeOffsetDistance()
var cubeColorString: String = ""
var xPos:Float = -cubeOffsetDistance
var yPos:Float = -cubeOffsetDistance
var zPos:Float = -cubeOffsetDistance
let xFloor:Float = -1.5
let yFloor:Float = -1.5
let zFloor:Float = -1.5
let floorGeo = SCNBox(width: 20, height: 0, length: 20, chamferRadius: 0)
let floor = SCNNode(geometry: floorGeo)
floor.position = SCNVector3(x: xFloor, y: yFloor, z: zFloor)
floor.name = "floor"
floor.opacity = 0.0
floor.physicsBody = SCNPhysicsBody(type: .kinematic, shape: nil)
floor.physicsBody?.collisionBitMask = 1
floor.physicsBody?.friction = 1.0
self.addChildNode(floor)
for _ in 0..<5 {
for _ in 0..<5 {
for _ in 0..<5 {
let cubeGeometry = SCNBox(width: CGFloat(cubeWidth), height: CGFloat(cubeWidth), length: CGFloat(cubeWidth), chamferRadius: 0)
let material = SCNMaterial()
material.diffuse.contents = randomColor()
//unwrap material (type any) and cast to uicolor for switch
if let unwrapColor: UIColor = material.diffuse.contents as? UIColor {
switch unwrapColor {
case UIColor.red:
cubeColorString = "red"
case UIColor.green:
cubeColorString = "green"
case UIColor.blue:
cubeColorString = "blue"
default:
cubeColorString = "black"
}
} else { print("Error unwrapping color") }
cubeGeometry.materials = [material, material, material, material, material, material]
let cube = SCNNode(geometry: cubeGeometry)
cube.name = cubeColorString
cube.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
cube.physicsBody?.restitution = 0.0
cube.physicsBody?.isAffectedByGravity = true
cube.physicsBody?.mass = 25.0
cube.physicsBody?.friction = 1.0
cube.physicsBody?.collisionBitMask = 1
cube.position = SCNVector3(x: xPos, y: yPos, z: zPos)
let details = CubeDetails(color: cubeColorString, position: cube.position)
//add cube details to the master dict
masterCubeDict[cube] = details
//print(masterCubeDict)
xPos += cubeWidth + spaceBetweenCubes
self.addChildNode(cube)
}
xPos = -cubeOffsetDistance
yPos += cubeWidth + spaceBetweenCubes
}
xPos = -cubeOffsetDistance
yPos = -cubeOffsetDistance
zPos += cubeWidth + spaceBetweenCubes
}
}
private func cubeOffsetDistance()->Float {
return (cubeWidth + spaceBetweenCubes) / 2
}
private func randomColor() -> UIColor{
var tmpColor: UIColor
let num = Int.random(in:0...2)
switch num {
case 0:
tmpColor = UIColor.red
case 1:
tmpColor = UIColor.blue
case 2:
tmpColor = UIColor.green
default:
tmpColor = UIColor.black
}
return tmpColor
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
用户实体
GameViewController
,创建轨道时调用的方法是:
import UIKit
import QuartzCore
import SceneKit
var myMasterCubeDict: [SCNNode: Cube.CubeDetails] = [:]
class GameViewController: UIViewController {
let gameCube = Cube()
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
// let scene = SCNScene(named: "art.scnassets/ship.scn")!
let scene = SCNScene()
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 2, y: 0, z: 20)
// create and add a light to the scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = UIColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
// init cube
myMasterCubeDict = gameCube.masterCubeDict
scene.rootNode.addChildNode(gameCube)
// retrieve the SCNView
let scnView = self.view as! SCNView
// set the scene to the view
scnView.scene = scene
// allows the user to manipulate the camera
scnView.allowsCameraControl = true
// show statistics such as fps and timing information
scnView.showsStatistics = true
// configure the view
scnView.backgroundColor = UIColor.black
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
scnView.addGestureRecognizer(tapGesture)
}
@objc
func handleTap(_ gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = self.view as! SCNView
// check what nodes are tapped
let p = gestureRecognize.location(in: scnView)
let hitResults = scnView.hitTest(p, options: [:])
// check that we clicked on at least one object
if hitResults.count > 0 {
// retrieved the first clicked object
let result = hitResults[0]
//get dict of same-color node
var dictOfSameColor = findAndReturnChain(boi: result.node)
// print(dictOfSameColor)
var finalNodes: [SCNNode] = [result.node]
var resFlag = 1
repeat {
var xSame: Bool = false
var ySame: Bool = false
var zSame: Bool = false
resFlag = 0
for node in finalNodes {
// var nodeX = node.position.x
for (key, value) in dictOfSameColor {
if(abs(node.position.x - value.position.x) < 0.7) {
xSame = true
}
if(abs(node.position.y - value.position.y) < 0.7) {
ySame = true
}
if(abs(node.position.z - value.position.z) < 0.7) {
zSame = true
}
//print("X-val: \(xDif) \nY-val: \(yDif) \nZ-val: \(zDif) \nColor: \(key.name) \n\n\n\n")
if (xSame && ySame ) {
if !(zSame) {
if (abs((node.position.z-value.position.z)) < 2) {
finalNodes.append(key)
dictOfSameColor.removeValue(forKey: key)
resFlag = 1
}
}
}
if (xSame && zSame) {
if !(ySame) {
if (abs((node.position.y-value.position.y)) < 2) {
finalNodes.append(key)
dictOfSameColor.removeValue(forKey: key)
resFlag = 1
}
}
}
if (ySame && zSame) {
if !(xSame) {
if (abs((node.position.x-value.position.x)) < 2) {
finalNodes.append(key)
dictOfSameColor.removeValue(forKey: key)
resFlag = 1
}
}
}
xSame = false
ySame = false
zSame = false
}
}
//print(finalNodes)
} while resFlag == 1
//print(finalNodes)
for node in finalNodes {
if node.name != "floor" {
node.removeFromParentNode()
}
}
//IMPLEMENT: Reset dicts to current state of the cube
myMasterCubeDict = updateMasterCubeDict(cube: gameCube)
dictOfSameColor.removeAll()
}
}
func findAndReturnChain(boi: SCNNode) -> [SCNNode:Cube.CubeDetails] {
var ret: [SCNNode:Cube.CubeDetails] = [:]
//find cubes with the same color
for (key, value) in myMasterCubeDict {
if value.color == boi.name {
ret[key] = value
}
}
return ret
}
func updateMasterCubeDict(cube: Cube) -> [SCNNode:Cube.CubeDetails] {
myMasterCubeDict.removeAll()
var newNode: SCNNode = SCNNode()
var newDetails = Cube.CubeDetails(color: "", position: SCNVector3Zero)
cube.enumerateChildNodes { (cube, stop) in
newNode = cube
if let newName = cube.name {
newDetails.color = newName
}
newDetails.position = cube.position
myMasterCubeDict[newNode] = newDetails
}
return myMasterCubeDict
}
override var shouldAutorotate: Bool {
return true
}
override var prefersStatusBarHidden: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
}
所以问题出在轨道列表上的@JoinColumn批注中,我将名称为 TRACK_ID 而不是 USER_ID