在Hibernate实体中映射外键

时间:2014-11-07 13:40:11

标签: java spring oracle hibernate

使用Spring Security编写Spring应用程序。它是我的用户和帐户角色数据库:

create table users (

  id int not null primary key,
  username varchar2(20) not null unique,
  password varchar2(20) not null,
  firstName varchar2(20),
  lastName varchar2(20),
  personalId varchar2(11) unique,
  city varchar2(40),
  address varchar2(40),
  email varchar2(30) unique,
  phone varchar2(9) unique,
  enabled number(1) not null
);

create table user_roles (
  id int primary key,
  name varchar2(20) not null,
  username varchar(20) constraint username_fk references users(username) not null
);

我的实体课程:

@Entity
@Table(name = "users")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue
    @Column(name = "id")
    private Integer id;
    @NotNull
    @Column(name = "username")
    private String username;
    @NotNull
    @Column(name = "password")
    private String password;
    @Column(name = "firstName")
    private String firstName;
    @Column(name = "lastName")
    private String lastName;
    @Column(name = "personalId")
    private String personalId;
    @Column(name = "city")
    private String city;
    @Column(name = "address")
    private String address;
    @Column(name = "email")
    private String email;
    @Column(name = "phone")
    private String phone;
    @NotNull
    @Column(name = "enabled")
    private int enabled;
    @OneToMany(mappedBy = "username")
    private Set<UserRole> userRoleSet = new HashSet<UserRole>(0);

@Entity
@Table(name = "user_roles")
public class UserRole implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    @Column(name = "id")
    private Integer id;
    @NotNull
    @Column(name = "name")
    private String name;
    @JoinColumn(name = "username")
    @ManyToOne(targetEntity = User.class)
    private String username;

当我尝试在我的系统中登录时,我有错误:

  

Hibernate:选择userrolese0_.username作为username3_1_0_,userrolese0_.id作为id1_0_0_,userrolese0_.id作为id1_0_1_,userrolese0_.name作为name2_0_1_,userrolese0_.username作为username3_0_1_来自user_roles userrolese0_其中userrolese0_.username =?   警告:org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL错误:1722,SQLState:42000   错误:org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ORA-01722:无效数字

我的类实现了UserDetailsS​​ervice:

    package pl.piotr.ibank.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import pl.piotr.ibank.daointerface.UserDao;
import pl.piotr.ibank.model.UserRole;

@Transactional(readOnly = true)
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {

        pl.piotr.ibank.model.User user = userDao.findByUsername(username);

        List<GrantedAuthority> authorities = buildUserAuthority(user
                .getUserRole());

        return buildUserForAuthentication(user, authorities);

    }

    private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {
        Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

        for (UserRole userRole : userRoles) {
            setAuths.add(new SimpleGrantedAuthority(userRole.getName()));
        }

        List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(
                setAuths);
        return result;
    }

    private UserDetails buildUserForAuthentication(
            pl.piotr.ibank.model.User user, List<GrantedAuthority> authorities) {
        return new User(user.getUsername(), user.getPassword(), true, true,
                true, true, authorities);
    }

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

我是这么认为的,我映射的表的foregin键很糟糕。示例查询from User从表中返回用户,但是当我尝试获取user_roles时,我有上述错误。请检查我映射的正确性。我使用的是Oracle数据库和Hiberante。

1 个答案:

答案 0 :(得分:1)

问题是,当您映射实体时,Hibernate期望外键是引用实体的id,即您应该映射user-id而不是username。

您的实体映射似乎也是错误的:您使用ManyToOne,目标实体为User,但属性类型为String。 AFAIK Hibernate会尝试将用户分配给username,这应该会失败。

所以表格应如下所示:

create table user_roles (
  id int primary key,
  name varchar2(20) not null,
  userid int constraint userid_fk references users(id) not null
);

UserRole中的映射应为:

@JoinColumn(name = "userid")
@ManyToOne
private User user;

加上User中的反向映射:

@OneToMany(mappedBy = "user")
private Set<UserRole> userRoleSet;

作为旁注,请注意id是HQL中的特殊关键字,即它始终引用实体的ID。如果id始终是唯一使用@Id注释的属性,那么它没有问题,但是如果您更改了该问题,您可能会遇到查询选择错误数据甚至失败的问题。