Java 如何修复';org.hibernate.TransientPropertyValueException';?

Java 如何修复';org.hibernate.TransientPropertyValueException';?,java,spring,hibernate,jpa,thymeleaf,Java,Spring,Hibernate,Jpa,Thymeleaf,我正在我的web应用程序中设置客户端购物车。在添加购物车类和他的服务之前,一切正常。现在,当我尝试启动Spring应用程序时,会显示以下错误: Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.myBookstoreProject.d

我正在我的web应用程序中设置客户端购物车。在添加购物车类和他的服务之前,一切正常。现在,当我尝试启动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)。但我的课上已经有了,在购物车课之前一切都很好

  • 用户类别:

    @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 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...
    }
    
    @实体
    公共类购物车{
    @身份证
    @GeneratedValue(策略=GenerationType.AUTO)
    私人长id;
    私人总收入;
    @OneToMany(mappedBy=“shoppingCart”,cascade=CascadeType.ALL,fetch=FetchType.LAZY)
    @杰索尼奥雷
    私人名单;
    @OneToOne(级联=级联类型.ALL)
    私人用户;
    //接球手和接球手。。。
    }
    
  • 购物车服务实施:

    @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;
        }
    
    }
    
    @服务
    公共类ShoppingCartServiceImpl实现ShoppingCartService{
    @自动连线
    私人CartItemService CartItemService;
    @自动连线
    私人购物车存储库购物车存储库;
    @凌驾
    公共购物车更新购物车(购物车购物车){
    BigDecimal cartTotal=新的BigDecimal(0);
    List cartItemList=cartItemService.findByShoppingCart(shoppingCart);
    对于(CartItem CartItem:cartItemList){
    如果(cartItem.getBook().getInStockNumber()>0){
    cartItemService.UpdateArtItem(cartItem);
    cartTotal=cartTotal.add(cartItem.getSubtotal());
    }
    }
    shoppingCart.setGrandTotal(cartTotal);
    shoppingCartRepository.save(shoppingCart);
    返回购物车;
    }
    }
    
  • 用户服务实现:

  • @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;
    }
@覆盖
@交易的
公共用户createUser(用户用户,设置用户角色)引发异常{
User localUser=userRepository.findByUsername(User.getUsername());
if(localUser!=null){
LOG.info(“用户{}已存在。将不执行任何操作。”,user.getUsername());
}否则{
for(UserRole-ur:userRoles){
roleRepository.save(ur.getRole());
}
user.getUserRoles().addAll(userRoles);
ShoppingCart ShoppingCart=新建ShoppingCart();//1
shoppingCart.setUser(user);//2
user.setShoppingCart(shoppingCart);//3
user.setUserShippingList(新ArrayList());//4
user.setUserPaymentList(新的ArrayList());//5
localUser=userRepository.save(用户);
}
返回本地用户;
}
此错误终止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);
    }
}
@springboot应用程序
公共类BookstoreProjectApplication实现CommandLineRunner{
公共静态void main(字符串[]args){
run(BookstoreProjectApplication.class,args);
}
@自动连线
私人用户服务;
@凌驾
公共无效运行(字符串…参数)引发异常{
用户user1=新用户();
user1.setFirstName(“新”);
user1.setLastName(“用户”);
user1.setUsername(“j”);
user1.setPassword(SecurityUtility.passwordEncoder().encode(“p”));
user1.setEmail(“newUser@gmail.com");
Set userRoles=new HashSet();
Role role1=新角色();
角色1.setRoleId(1);
角色1.setName(“角色用户”);
添加(新的UserRole(user1,role1));
createUser(user1,userRoles);
}
}

如果我对方法体(run)进行注释,则在创建新用户之前服务器运行良好,然后出现错误。

您正在从
userRole
持久化
角色,然后将其分配给用户,但保存后不会将持久化的实体分配给角色,因此,
userRole
中的
角色
不再与持久化的角色相同,也没有生成的
id
。当您保存一个实体,然后将其或其父实体作为值添加到另一个实体,并且没有完全级联时,您添加的是另一个对象。这意味着,使用“保存”中的返回对象,并将其重新分配给保存的对象,然后该对象应该可以正常工作,或者使用“到处级联”并仅保存1个对象

TLDR<代码>用户角色
角色
与数据库中的
角色
实体不同

编辑1:

Set userRoles
更改为
List userRoles
(否则您必须将其转换100次,因为您无法在遍历集合时替换集合的值),然后替换

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

for(int i=0;i
您是否尝试从您的用户字段上的
购物车中删除级联类型?是的,但仍然是相同的错误:
原因:org.hibernate.TransientPropertyValueException:对象引用未保存的临时实例-在刷新之前保存临时实例:com.myBookstoreProject.domain.security.UserRole.role->com.myBookstoreProject.domain.security.Role
太好了!这个解决方案似乎工作正常。只有一个问题:在回答的第一行中,您说:“保存后您不会将持久化实体分配给角色,因此userRole中的角色不再与持久化实体相同。”。为什么在添加购物车类之前,应用程序会运行
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())
}