Jpa多对多如何仅将数据插入2个表
Posted
技术标签:
【中文标题】Jpa多对多如何仅将数据插入2个表【英文标题】:Jpa many-to-many how can I insert data into 2 tables only 【发布时间】:2014-10-10 08:50:29 【问题描述】:我有一些问题。
我有 3 张桌子:
users (id, name, ..)
roles (id, name)
user-role (user_id, role_id)
当我执行多对多关系并执行 save() 时,我有 3 个插入。
用户:
@Entity
@Table(name = "user")
public class User implements Serializable
public static final String UK_EMAIL = "uk_email";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST, CascadeType.MERGE)
@JoinTable(
name = "system_user_role",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = id")
)
private List<SystemRole> userRole;
public List<SystemRole> getUserRole()
return userRole;
系统角色;
@Entity
@Table(name = "system_role")
public class SystemRole implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column
private String name;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "system_user_role",
joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")
)
private List<User> users;
public List<User> getUsers()
return users;
public void setUsers(List<User> users)
this.users = users;
public Long getId()
return id;
public void setId(Long id)
this.id = id;
public String getName()
return name;
public void setName(String name)
this.name = name;
请告诉我,我可以只将数据插入 2 个表中,只插入(用户和用户角色? 我有角色列表,创建新用户时不需要添加新角色。
所以,当我这样做时:
SystemRole role1 = systemRoleService.findOne("ROLE_ADMIN");
userForm.setUserRole(Lists.newArrayList(role1));
....
final User saved = userRepository.save(user);
....
我收到一个错误:
org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist:...
如果我这样做:
@Service("userService")
@Transactional
public class UserServiceImpl implements UserDetailsService, ResourceService<User>
private final static Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);
@Autowired
private UserDAO userRepository;
@Autowired
private SystemRoleDAO systemRoleRepository;
@Override
@Transactional(rollbackFor = ResourceException.class)
public User create(User user) throws ResourceException
try
SystemRole role1 = systemRoleRepository.findOne(6l);
user.setUserRole(Lists.newArrayList(role1));
user.setId(62l); // !!! if set user ID - it works CORRECT
final User saved = userRepository.save(user);
return saved;
catch (DataIntegrityViolationException ex)
...
用户DAO:
@Repository
public interface UserDAO extends JpaRepository<User, Long>
...
SystemRoleDAO:
@Repository
public interface SystemRoleDAO extends JpaRepository<SystemRole, Long>
它有效,但我有 3 个插入。
当我创建一个新用户时,我需要从列表中选择一个角色,将其添加到用户并保存新用户。
非常感谢。
【问题讨论】:
你如何分配角色?看起来您正在创建新角色而不是使用现有角色。请避免使用像List
这样的原始类型。请改用List<SystemRole>
。
我猜有一个插入,因为角色,因为您创建一个新角色而不是分配一个现有角色,但您需要发布创建和保存的代码。
@user1647166 我编辑了你的问题,代码格式有问题。你能检查一下这个问题:***.com/questions/17887055/… 吗?看起来相关。
@Tom,谢谢,但我之前看过这篇文章,我有不同的情况。我需要使用存在的角色(我将从列表中选择它们),而不是每次创建新用户时都创建新角色。
看起来systemRoleService.findOne
在你的role
object 上调用detach
。如果是这样,请不要这样做。 detach
用于高级跨会话操作,而不是常规对象操作。
【参考方案1】:
@实体 @Table(name = "用户")
公共类用户实现可序列化
public static final String UK_EMAIL = "uk_email";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST, CascadeType.MERGE) //Make CascadeType.Detached this should solver your problem
@JoinTable(
name = "system_user_role",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = id")
)
private List<SystemRole> userRole;
public List<SystemRole> getUserRole()
return userRole;
【讨论】:
【参考方案2】:我猜你的 userRepository.save() 方法中的代码正在调用
entityManager.persist(user);
你应该打电话
entityManager.merge(user);
通过这样做,Hibernate 不会插入新的角色,而是检查具有相同 ID 的角色是否已经存在,如果是这种情况,该角色将附加到用户实体(前提是级联类型包括合并操作)。
您需要调用合并的原因是您正在使用已加载的角色实体(通过 systemRoleService.findOne("ROLE_ADMIN"))然后从持久性上下文中分离,因此当您尝试时该实体被分离保存用户。如果没有分离 Role,您可以在 User 实体上调用 persist() 而不是 merge()。
【讨论】:
嗨,谢谢,但我使用org.springframework.data.jpa.repository.JpaRepository
接口并从中调用方法save()
。
看看这个***.com/questions/15943783/…
我已经更改了我的代码,但是... :( 请看一下更改。谢谢。
如果我打电话给user.setId()
- 它工作正常,但我这样做只是为了测试。保存前我不知道用户 ID...
是的,因为在这种情况下,存储库将调用 merge() 而不是 persist()。您必须了解才能弄清楚您的交易中发生了什么。尝试在 TRACE 级别记录 org.springframework.transaction以上是关于Jpa多对多如何仅将数据插入2个表的主要内容,如果未能解决你的问题,请参考以下文章