假设我有Category
表,每个类别都有父类和子类。但是父级是可选的,因此它可能没有父级。
CREATE TABLE `Category` (
`categoryID` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`parentCategoryID` int(11) DEFAULT NULL,
PRIMARY KEY (`categoryID`),
KEY `category_category_fk` (`parentCategoryID`),
CONSTRAINT `category_category_fk` FOREIGN KEY (`parentCategoryID`) REFERENCES `Category` (`categoryID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
这是hbm文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated May 16, 2013 12:50:14 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="model.Category" table="Category">
<id name="categoryId" type="java.lang.Integer">
<column name="categoryID" />
<generator class="identity" />
</id>
<many-to-one name="parentCategory" class="model.Category" fetch="select" cascade="all">
<column name="parentCategoryID" />
</many-to-one>
<property name="name" type="string">
<column name="name" length="100" />
</property>
<set name="subCategories" table="Category" inverse="true" lazy="true" fetch="select">
<key>
<column name="parentCategoryID" />
</key>
<one-to-many class="model.Category" />
</set>
</class>
</hibernate-mapping>
我使用Hibernate Tools来生成HBM和DAO。
现在的问题是,每当我试图坚持Category
没有父级时,Hibernate在表格中添加了两行,每一行都设置为NULL
,第二个是我放置的值和parentCategoryID
引用的第一行。
如果我认为它与cascade
选项有关,但是每次删除它时,Java都会抛出异常,例如.... references an unsaved transient instance - save the transient instane before flushing
任何人都知道如何在这里正确地做到这一点?我上周刚刚开始学习Spring-Hibernate,所以这对我来说很新鲜。提前谢谢。
修改(相关代码)
model.Category
/**
* Category generated by hbm2java
* model.Category
*/
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="categoryId")
public class Category implements java.io.Serializable {
private Integer categoryId;
private Category parentCategory;
private String name;
@JsonIgnore
private Set<Category> subCategories = new HashSet<Category>(0);
public Category() {
}
public Category(Category parentCategory,
String name
Set<Category> subCategories) {
this.parentCategory = parentCategory;
this.name = name;
this.subCategories = subCategories;
}
public Integer getCategoryId() {
return this.categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public Category getParentCategory() {
return this.parentCategory;
}
public void setParentCategory(Category parentCategory) {
this.parentCategory = parentCategory;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Set<Category> getSubCategories() {
return this.subCategories;
}
public void setSubCategories(Set<Category> subCategories) {
this.subCategories = subCategories;
}
}
dao.CategoriesDao
/**
* Home object for domain model class Category.
* @see model.Category
* @author Hibernate Tools
*/
@Repository
public class CategoriesDao {
private static final Log log = LogFactory.getLog(CategoriesDao.class);
@Autowired
private SessionFactory sessionFactory;
public void persist(Category transientInstance) {
log.debug("persisting Category instance");
try {
sessionFactory.getCurrentSession().persist(transientInstance);
log.debug("persist successful");
} catch (RuntimeException re) {
log.error("persist failed", re);
throw re;
}
}
public void attachDirty(Category instance) {
log.debug("attaching dirty Category instance");
try {
sessionFactory.getCurrentSession().saveOrUpdate(instance);
log.debug("attach successful");
} catch (RuntimeException re) {
log.error("attach failed", re);
throw re;
}
}
public void attachClean(Category instance) {
log.debug("attaching clean Category instance");
try {
sessionFactory.getCurrentSession().lock(instance, LockMode.NONE);
log.debug("attach successful");
} catch (RuntimeException re) {
log.error("attach failed", re);
throw re;
}
}
public void delete(Category persistentInstance) {
log.debug("deleting Category instance");
try {
sessionFactory.getCurrentSession().delete(persistentInstance);
log.debug("delete successful");
} catch (RuntimeException re) {
log.error("delete failed", re);
throw re;
}
}
public Category merge(Category detachedInstance) {
log.debug("merging Category instance");
try {
Category result = (Category) sessionFactory.getCurrentSession()
.merge(detachedInstance);
log.debug("merge successful");
return result;
} catch (RuntimeException re) {
log.error("merge failed", re);
throw re;
}
}
public Category findById(java.lang.Integer id) {
log.debug("getting Category instance with id: " + id);
try {
Category instance = (Category) sessionFactory
.getCurrentSession().get("model.Category", id);
if (instance == null) {
log.debug("get successful, no instance found");
} else {
log.debug("get successful, instance found");
}
return instance;
} catch (RuntimeException re) {
log.error("get failed", re);
throw re;
}
}
public List<Category> findByExample(Category instance) {
log.debug("finding Category instance by example");
try {
List<Category> results = (List<Category>) sessionFactory
.getCurrentSession().createCriteria("model.Category")
.add(create(instance)).list();
log.debug("find by example successful, result size: "
+ results.size());
return results;
} catch (RuntimeException re) {
log.error("find by example failed", re);
throw re;
}
}
}
修改(添加控制器)
controller.AddCategoryController
@Controller
@RequestMapping("/categories/addcategory.*")
public class AddCategoryController {
@Autowired
private CategoriesService categoriesService;
@InitBinder("Category")
public void initBinder(WebDataBinder binder) {
binder.setValidator(new CategoryValidator());
/**
* Will put NULL for empty string instead of trying to put value
* so later can be used to NULL empty parentCategory
*/
binder.registerCustomEditor(Category.class, new StringTrimmerEditor(true));
}
@RequestMapping(method = RequestMethod.GET)
public String view(Model model) {
this.setFormAttributes(model, new Category());
return "/categories/addcategory";
}
/**
* Called on form submission
*/
@RequestMapping(method = RequestMethod.POST)
public String create(
@ModelAttribute("Category") @Valid Category category,
BindingResult result, Model model) {
if (result.hasErrors()) {
this.setFormAttributes(model, category);
return "/categories/addcategory";
}
this.categoriesService.save(category);
return "redirect:/categories/listcategories.htm";
}
private void setFormAttributes(Model model, Category category) {
model.addAttribute("Category", category);
model.addAttribute("categories", this.categoriesService.listCategories());
}
}