JPA Составные внешние первичные ключи - PullRequest
0 голосов
/ 14 мая 2018

Таким образом, у меня в настоящее время есть база данных с пользовательской информацией, и что определяет пользователя, это user_id.

Затем у меня есть таблица с именем token, в которой первичным ключом являются token_id и user_id, а остальная информация - база данных «один ко многим».

@Entity
@Table(name = "user")
public class User implements Serializable {
    @Id
    @Column(name = "user_id")
    private long userId;
    //Other variables and getters and setters

    @OneToMany(orphanRemoval = true, mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @Access(AccessType.PROPERTY) //I need this as is since I have other things in the setter 
    private List<Token> tokens = new ArrayList<>();

    public List<Token> getTokens() {
        return tokens;
    }

    public void setTokens(List<Token> tokens) {
        this.tokens = tokens;
    }
}

После этого фрагмента кода у меня есть класс токена

public class Token implements Serializable{
    @Id
    private long tokenId;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @Column(nullable = false)
    private String token;

    @Access(AccessType.PROPERTY)
    private Instant lastUsed;

    @Column(nullable = false)
    private Instant dateCreated;

    @Transient
    private boolean expired;

    //Getters and setters go here


    //Static methods and generating the token
    private static String generateToken(){
        Random random = new Random();
        byte[] randomString = new byte[256];
        random.nextBytes(randomString);
        return Base64.encodeBase64String(randomString);
    }

    public static Token generateUserToken(User user){
        Token token = new Token();
        token.setTokenId(new Random().nextLong());
        token.setUser(user);
        token.setDateCreated(Instant.now());
        token.setToken(generateToken());

        return token;
    }
    //Static methods and generating the token
}

Теперь по какой-то причине всякий раз, когда User user не помечен как @Id, он работает (даже если в базе данных это первичный ключ).

Любая помощь;

application.properties:

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL57InnoDBDialect

spring.jpa.show-sql=true
logging.level.org.hibernate.type=TRACE

Вывод SQL:

Hibernate: insert into tokens (date_created, last_used, token, user_id, token_id) values (?, ?, ?, ?, ?)
binding parameter [1] as [TIMESTAMP] - [2018-05-14T08:29:00.719764Z]
binding parameter [2] as [TIMESTAMP] - [null] //This is okay to be null this is last_used
binding parameter [3] as [VARCHAR] - [<Token too long to write in question>] //Actual data type is LONGTEXT
binding parameter [4] as [BIGINT] - [null] //this is a problem (user_id should not be - should be a long numebr such as: 5531405900210671089)
binding parameter [5] as [BIGINT] - [0] //this is a problem (token_id should be a long number such as: -8824825685434914749)
SQL Error: 1048, SQLState: 23000
Column 'user_id' cannot be null

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Это «производная личность», поэтому Token требуется @IdClass, например:

public class TokenId implements Serializable {
    private long tokenId; // matches the name of the attribute
    private long user;  // matches name of attribute and type of User PK
    ...
}

Тогда Token необходимо указать @IdClass следующим образом:

@Entity
@IdClass(TokenId.class)
public class Token {
    ...
}

Производные идентификаторы обсуждаются (с примерами) в спецификации JPA 2.1 в разделе 2.4.1.

0 голосов
/ 14 мая 2018

Вам не нужно аннотировать user_id с @Id в токене: вы видели, что это работает. Также в базе данных достаточно определить первичный ключ TokennId таблицы Tokenas. Конечно, user_id должен быть установлен как внешний ключ, который не должен быть нулевым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...