Ily*_*lov 9 java hibernate spring-data
我在我的分贝两个表Brand
和Product
下一个简单的结构:
| 品牌| id PK |
| 产品| id PK | brand_id FK |
和该表的实体:
@Entity
@Table(name = "Brand")
public class Brand {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "brand")
private String brand;
/* getters and setters */
}
Run Code Online (Sandbox Code Playgroud)
@Entity
@Table(name = "Product")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "brand_id")
private Brand brand;
/* getters and setters */
}
Run Code Online (Sandbox Code Playgroud)
当我使用Spring-Data时,我拥有存储库和服务以及Brand的实现:
@Repository
public interface BrandRepository extends JpaRepository<Brand, Long> {
Brand findByBrand(String brand);
}
Run Code Online (Sandbox Code Playgroud)
public interface BrandService {
Brand findByBrand(String brand);
}
Run Code Online (Sandbox Code Playgroud)
@Service
public class BrandServiceImpl implements BrandService {
@Autowired
private BrandRepository brandRepository;
@Override
public Brand findByBrand(String brand) {
return brandRepository.findByBrand(brand);
}
}
Run Code Online (Sandbox Code Playgroud)
和产品:
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
}
Run Code Online (Sandbox Code Playgroud)
public interface ProductService {
Product save(Product product);
}
Run Code Online (Sandbox Code Playgroud)
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductRepository productRepository;
@Override
public Product save(Product product) {
return productRepository.save(product);
}
}
Run Code Online (Sandbox Code Playgroud)
目标是保存Product对象.如果品牌对象在db中不存在,则应自动保存,否则应设置为Product:
Brand brand = brandService.findByBrand(brandName);
if (brand == null) {
brand = new Brand();
brand.setBrand("Some name");
}
product.setBrand(brand);
productService.save(product);
Run Code Online (Sandbox Code Playgroud)
如果具有指定brandName的Brand对象不在我的数据库中,它可以正常工作.但如果是我得到:
PersistentObjectException: detached entity passed to persist
Run Code Online (Sandbox Code Playgroud)
为品牌.
我可以将级联类型更改为MERGE,它将正常工作.但是,如果我使用MERGE级联类型运行代码,并且指定brandName的Brand对象不在我的数据库中,我得到
IllegalStateException:
org.hibernate.TransientPropertyValueException:
object references an unsaved transient instance - save the transient instance before flushing
Run Code Online (Sandbox Code Playgroud)
对于品牌(这真的不会感到惊讶).
级联类型应该是什么?我做错了什么?
Leo*_*ruz 18
简短回答:
级联注释没有问题.您不应该依赖自动级联并在服务层内手动实现此逻辑.
答案很长:
您有两种情况:
场景1发生是因为JPA在持久化PRODUCT(CascadeType.ALL)后试图保持BRAND.一旦BRAND存在,您就会出错.
场景2发生,因为JPA并没有试图坚持BRAND(CascadeType.MERGE)并且BRAND之前没有持久化.
很难找到解决方案,因为有很多抽象层.Spring数据提取JPA,它抽象出抽象JDBC等的Hibernate.
一个可能的解决方案是使用EntityManager.merge而不是EntityManager.persist,以便CascadeType.MERGE可以工作.我相信你可以做到重新实现Spring Data保存方法.这里有一些参考:Spring Data:覆盖保存方法
另一种解决方案是简短的回答.
例:
@Override
public Product save(Product product, String brandName) {
Brand brand = brandService.findByBrand(brandName);
if (brand == null) {
brand = brandService.save(brandName);
}
return productRepository.save(product);
}
Run Code Online (Sandbox Code Playgroud)
在方法中添加@Transactional 将整个讨论整合到一个 PersistenceContext 以及优化查询(更少的 hibernate sql 查询)
@Override
@Transactional
public Product save(Product product, String brandName) {
Brand brand = brandService.findByBrand(brandName);
if (brand == null) {
brand = brandService.save(brandName);
}
return productRepository.save(product);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
14550 次 |
最近记录: |