java - 如何修复 ' org.hibernate.TransientPropertyValueException'?

标签 java spring hibernate jpa thymeleaf

我正在我的网络应用程序中设置客户端购物车。在添加购物车类和他的服务之前一切都很好。现在,当我尝试启动 Spring 应用程序时,会显示此错误:

Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.myBookstoreProject.domain.security.UserRole.role -> com.myBookstoreProject.domain.security.Role

我寻找解决方案,但发现我的应用程序实体存在问题。解决方案是将 (cascade=CascadeType.ALL) 添加到导致错误的实体。但我的类(class)已经有了它,并且在购物车类(class)之前一切都很好。

  • 用户类别:

    @Entity
    public class User implements UserDetails {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name = "id", nullable = false, updatable = false)
        private Long id;
        private String username;
        private String password;
        private String firstName;
        private String lastName;
    
        @Column(name = "email", nullable = false, updatable = false)
        private String email;
        private String phone;
        private boolean enabled = true;
    
        @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
        @JsonIgnore 
        private Set<UserRole> userRoles = new HashSet<>();
    
        @OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
        private List<UserShipping> userShippingList;
    
        @OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
        private List<UserPayment> userPaymentList;
    
        @OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
        private ShoppingCart shoppingCart;
    
        // getters and setters..
    }
    
  • 角色

    @Entity 
    public class Role {
    
        @Id
        private int roleId;
        private String name;
    
        @OneToMany(mappedBy = "role", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
        private Set<UserRole> userRoles = new HashSet<UserRole>();
    
        // getters and setters..
    }
    
  • UserRole 类:

    @Entity
    @Table(name = "user_role")
    public class UserRole {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long userRoleId;
    
        @ManyToOne(fetch = FetchType.EAGER)
        @JoinColumn(name = "user_id")
        private User user;
    
        @ManyToOne(fetch = FetchType.EAGER)
        @JoinColumn(name = "role_id")
        private Role role;
    
        // getters and setters..
    }
    
  • 购物车:

    @Entity
    public class ShoppingCart {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        private BigDecimal GrandTotal;
    
        @OneToMany(mappedBy="shoppingCart", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
        @JsonIgnore
        private List<CartItem> cartItemList;
    
        @OneToOne(cascade=CascadeType.ALL)
        private User user;
        // getters and setters...
    }
    
  • 购物车服务实现:

    @Service
    public class ShoppingCartServiceImpl implements ShoppingCartService {
    
        @Autowired
        private CartItemService cartItemService;
    
        @Autowired
        private ShoppingCartRepository shoppingCartRepository;
    
        @Override
        public ShoppingCart updateShoppingCart(ShoppingCart shoppingCart) {
            BigDecimal cartTotal = new BigDecimal(0);
    
            List<CartItem> cartItemList = cartItemService.findByShoppingCart(shoppingCart);
    
            for (CartItem cartItem : cartItemList) {
                if (cartItem.getBook().getInStockNumber() > 0) {
                    cartItemService.updateCartItem(cartItem);
                    cartTotal = cartTotal.add(cartItem.getSubtotal());
                }
            }
    
            shoppingCart.setGrandTotal(cartTotal);
    
            shoppingCartRepository.save(shoppingCart);
    
            return shoppingCart;
        }
    
    }
    
  • 用户服务实现:

在这个类方法中,我添加了“@Transactional”和 5 行购物车,然后出现错误

@Override
@Transactional
    public User createUser(User user, Set<UserRole> userRoles) throws Exception {
        User localUser = userRepository.findByUsername(user.getUsername());

        if (localUser != null) {
            LOG.info("user {} already exists. Nothing will be done.", user.getUsername());
        } else {
            for (UserRole ur : userRoles) {
                roleRepository.save(ur.getRole());
            }

            user.getUserRoles().addAll(userRoles);

            ShoppingCart shoppingCart = new ShoppingCart(); // 1
            shoppingCart.setUser(user); // 2
            user.setShoppingCart(shoppingCart); // 3

            user.setUserShippingList(new ArrayList<UserShipping>()); //4
            user.setUserPaymentList(new ArrayList<UserPayment>()); // 5

            localUser = userRepository.save(user);
        }
        return localUser;
    }

此错误会终止 Spring 应用程序,并且仅在 MySql 中创建表而不添加行。

编辑 1: 当我尝试向我的应用程序添加新用户时会出现问题。这是我的引导主类:

@SpringBootApplication
public class BookstoreProjectApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(BookstoreProjectApplication.class, args);
    }

    @Autowired
    private UserService userService;

    @Override
    public void run(String... args) throws Exception {
        User user1 = new User();
        user1.setFirstName("New");
        user1.setLastName("User");
        user1.setUsername("j");
        user1.setPassword(SecurityUtility.passwordEncoder().encode("p"));
        user1.setEmail("newUser@gmail.com");
        Set<UserRole> userRoles = new HashSet<>();
        Role role1 = new Role();
        role1.setRoleId(1);
        role1.setName("ROLE_USER");
        userRoles.add(new UserRole(user1, role1));

        userService.createUser(user1, userRoles);
    }
}

如果我注释方法主体(run),服务器运行得很好,直到创建新用户,然后出现错误。

最佳答案

您正在坚持 roles来自您的userRole然后将它们分配给用户,但在保存它们后,您不会将持久实体分配给角色,因此 rolesuserRole与持久化的不再相同,也没有生成的 id 。当您保存一个实体,然后将其或父实体作为值添加到另一个实体并且没有完全级联时,您将添加一个不同的对象。这意味着,使用 save 的返回对象并将其重新分配给您保存的对象,然后应该没问题,或者在各处使用级联并仅保存 1 个对象。

TLDR; userRoles 'roleRole 不一样数据库中的实体。

编辑1:

更改Set<UserRole> userRolesList<UserRole> userRoles (否则你必须将其转换大约 100 次,因为你无法在遍历 Set 时替换它的值)然后替换

for (UserRole ur : userRoles) {
  roleRepository.save(ur.getRole());
}

for (int i = 0; i < userRoles.size(); i++) {
  userRoles.get(i).setRole(roleRepository.save(userRoles.get(i).getRole())
}

关于java - 如何修复 ' org.hibernate.TransientPropertyValueException'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57851900/

相关文章:

java - 避免关闭钩子(Hook)

java - 错误 : java. lang.NumberFormatException:

spring - 使用 Spring 和 Hibernate 与额外列的 ManyToMany 关系并且没有复合键概念

java - Spring Cloud Gateway 返回空响应

java - hibernate 2 : mysql : socket write error

hibernate - Play 框架连接超时问题

java - 如何使用一组可变的字符串进行类似查询?

java - 如何将驻留在 Amazon ec2 实例中的 Tomcat 7 server.xml 文档库指向 Amazon S3 存储桶中的文件夹

java - 对于 Java 版 YouTube API V3,访问 token 始终会在 1 小时后过期

java - 异常(exception):JTA事务意外回滚(可能是由于超时)