简体   繁体   English

从另一个实体引用一个实体

[英]Referencing an Entity from another Entity

I have two Entities in my Java EAR: User and Password. 我的Java EAR中有两个实体:用户和密码。 These, of course, have corresponding tables in the database: Users and Passwords. 当然,这些在数据库中具有对应的表:用户和密码。 The passwords table contains the user's id as a foreign key. 密码表包含用户ID作为外键。 So my question is how do I pull the password entry from the Passwords table when the User is created from the Users table using purely annotations? 所以我的问题是,当使用纯注解从Users表中创建User时,如何从Passwords表中提取密码条目? I'm at a loss. 我很茫然。

I don't want to have to use business logic to access the user's related password entity -- so I need the container to do this for me. 我不想使用业务逻辑来访问用户的相关密码实体,因此我需要容器为我完成此任务。

SCCE: SCCE:

@Entity
@Table(name = "USERS")
public class User{
    @Id
    @Basic(optional = false)
    @NotNull
    @Column(name = "IDENTIFIER", nullable = false)
        private Long identifier;

    @JoinColumn(name = "UserIdentifier")
    @OneToOne
    private Password password;

    // getters, setters, and other User related information such as username
}

@Entity
@Table(name = "PASSWORDS")
public class Password{
    @Id
    @Basic(optional = false)
    @NotNull
    @Column(name = "IDENTIFIER", nullable = false)
        private Long identifier;

    @JoinColumn(name = "USERIDENTIFIER", referencedColumnName = "IDENTIFIER", nullable = false)
    @OneToOne(optional = false, fetch = FetchType.EAGER)
        private User useridentifier;
    //getters, setters, and other password related fields such as the password it's self
}

The entity classes just establish the data and relationships. 实体类只是建立数据和关系。 You retrieve the data from a particular instance in your business logic. 您可以从业务逻辑中的特定实例检索数据。 You've established the relationships with the @OneToOne annotations on the User and Password properties. 您已经在User和Password属性上使用@OneToOne批注建立了关系。 What you're missing is a persistent field for the Password entity. 您缺少的是Password实体的持久字段。

@Entity
@Table(name = "PASSWORDS")
public class Password{
    @Id
    @Basic(optional = false)
    @NotNull
    @Column(name = "IDENTIFIER", nullable = false)
    private Long identifier;

    @JoinColumn(name = "USERIDENTIFIER", referencedColumnName = "IDENTIFIER", nullable = false)
    @OneToOne(mappedBy = "password", optional = false, fetch = FetchType.EAGER)
    private User useridentifier;

    @NotNull
    private String passwordValue;

    // getters/setters go here, since your annotated fields are private 
}

You can then traverse the relationships by retrieving a User instance and navigating to the relationship field. 然后,您可以通过检索User实例并导航到关系字段来遍历关系。 So your business logic might look something like this: 因此,您的业务逻辑可能看起来像这样:

@PersistenceContext
EntityManager em;

Long userIdInput = ...;
String passwordInput = ...;

User user = em.find(User.class, userIdInput);
// compare the input password with the stored password
// retrieve the Password instance by navigating to the relationship field
if (passwordInput.equals(user.getPassword().getPasswordValue()) {
    // passwords match
} else {
    // passwords don't match
}

You've got your usernames as Long values, which is...odd. 您的用户名是Long值,这很奇怪。 And you should probably look into how to handle securely handle storing password values in your database, as it's not a good practice to store them unencrypted. 您可能应该研究如何安全地处理将密码值存储在数据库中,因为不加密地存储密码不是一个好习惯。 But this is gist of JPA. 但这是JPA的要旨。

Edit: The owner of the relationship needs to be set using mappedBy, as pointed out by @neil-stockton. 编辑:关系的所有者需要使用@ neil-stockton指出的mapByBy设置。

Turns out the answer was simple enough. 原来答案很简单。 I had the right annotations but I needed a few extra things. 我有正确的注释,但我需要一些额外的东西。 Below is the relevant code for both entities. 以下是两个实体的相关代码。

@Entity
@Table(name = "USERS")
public class User{
    @Id
    @Basic(optional = false)
    @NotNull
    @Column(name = "IDENTIFIER", nullable = false)
        private Long identifier;

    @JoinColumn(referencedColumnName = "PASSWORDS.USERIDENTIFIER", name="USERS.IDENTIFIER")
    @OneToOne
    private Password password;

    // getters, setters, and other User related information such as username
}

@Entity
@Table(name = "PASSWORDS")
public class Password{
    @Id
    @Basic(optional = false)
    @NotNull
    @Column(name = "IDENTIFIER", nullable = false)
        private Long identifier;

    @JoinColumn(name = "USERIDENTIFIER", referencedColumnName = "IDENTIFIER", nullable = false)
    @OneToOne(optional = false, fetch = FetchType.EAGER)
        private User useridentifier;
    //getters, setters, and other password related fields such as the password it's self
}

So for future stackers who have one entity that references another entity, you should specify the name and referencedColumnName of the JoinColumn annotation to get the container to pull in the related entity. 因此,对于将来拥有一个实体引用另一个实体的堆栈器,您应该指定JoinColumn批注的名称和referencedColumnName来获取要拉入相关实体的容器。 I was able to pull in the correct password row from the database by doing this. 通过这样做,我能够从数据库中提取正确的密码行。 Note that the joincolumn annotation in the user entity must have the table name as well and that the same annotation in the password entity must NOT have the table names. 请注意,用户实体中的joincolumn批注也必须具有表名,而密码实体中的同一批注必须不能具有表名。 It won't work otherwise -- believe me, I tried it and got a StackOverflow error. 否则它将无法正常工作-相信我,我尝试了一下并出现了StackOverflow错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM