我尝试通过SpringMVC和JPA将多对一关系持久化。
我的观点如下:
<form:form modelAttribute="wordpair" action="addWordPair" method="post">
<label for="semanticUnitOne">Enter word one: </label>
<form:input path="semanticUnitOne"/>
<br/>
<label for="semanticUnitTwo">Enter word two: </label>
<form:input path="semanticUnitTwo"/>
<br/>
<div class="form-group">
<label for="dictionary">Dictionary</label>
<form:select path="dictionary" cssClass="selectpicker" items="${dictionaries}" itemLabel="name" itemValue="id">
<%--<form:options items="${dictionaries}" itemValue="id" itemLabel="name"/>--%>
</form:select>
</div>
<input type="submit" class="btn" value="Add word pair"/>
</form:form>
<div class="control-group">
</div>
</div>
控制器如下:
@Controller
public class WordPairController {
@Autowired
WordPairService wordPairService;
@Autowired
DictionaryService dictionaryService;
@RequestMapping(value = "createWordPair", method = RequestMethod.GET)
public String createWordPair(Model model) {
model.addAttribute("wordpair", new WordPair());
model.addAttribute("dictionaries", this.dictionaryService.findAll());
return "addWordPair";
}
@RequestMapping(value = "addWordPair", method = RequestMethod.POST)
public String addWordPair(@ModelAttribute("wordpair") WordPair wordPair, BindingResult result, Dictionary dictionary) {
wordPair.setDictionary(dictionary);
wordPairService.save(wordPair);
return "addWordPair";
}
@RequestMapping(value = "wordPairGet", method = RequestMethod.GET)
public String wordPairGet(Model model) {
model.addAttribute("wordPair", wordPairService.findAllWordPairs());
return "wordPairGet";
}
}
字典的实体如下:
@Entity
public class Dictionary {
@Id
@GeneratedValue
private Long id;
private String name;
private String comment;
@OneToMany(mappedBy = "dictionary", cascade = CascadeType.All, fetch=FetchType.EAGER)
private List<WordPair> wordPairs;
和wordpair实体:
@Entity
@Table
public class WordPair {
@Id
@GeneratedValue
private Long id;
private String semanticUnitOne;
private String semanticUnitTwo;
private int rating;
@ManyToOne(fetch = FetchType.EAGER, cascade = javax.persistence.CascadeType.All)
private Dictionary dictionary;
还有一项服务和DAO,
@Repository("dictionaryDao")
public class DictionaryDaoImpl implements DictionaryDao {
@PersistenceContext
private EntityManager em;
public Dictionary save(Dictionary dictionary) {
em.persist(dictionary);
em.flush();
return dictionary;
}
public List<Dictionary> findAllDictionaries() {
List<Dictionary> result = em.createQuery("SELECT d FROM Dictionary d", Dictionary.class).getResultList();
return result;
}
}
@Repository("wordPairRepository")
public class WordPairDaoImpl implements WordPairDao {
@PersistenceContext
private EntityManager em;
public List<WordPair> findAllWordPairs() {
List<WordPair> result = em.createQuery("SELECT p FROM WordPair p", WordPair.class).getResultList();
return result;
}
public WordPair save(WordPair wordPair) {
em.persist(wordPair);
em.flush();
return wordPair;
}
问题是,当我尝试将WordPair
和Dictionary
实体持久化时,hibernate会持久保存新的Dictionary实体,然后通过附加新词典来保留新的WordPair实体。如何附加我用表单选择的现有字典实体:在视图中选择项目?
如果我改变
@ManyToOne(fetch = FetchType.EAGER, cascade = javax.persistence.CascadeType.All)
WordPair中选项合并或其他东西,它给出了
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException:对象引用一个 未保存的瞬态实例 - 保存之前的瞬态实例 冲洗:
答案 0 :(得分:2)
我正在使用Spring JPA和Hibernate 5,我让hibernate创建表。
我有实体:
@Entity(name = "DICTIONARY")
public class Dictionary {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String comment;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name="DICTIONARY_ID")
private List<WordPair> wordPairs;
和
@Entity(name = "WORDPAIR")
public class WordPair {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String semanticUnitOne;
private String semanticUnitTwo;
private int rating;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Dictionary dictionary;
我有JPA Repostories,注意@Transaction很重要
@Repository
@Transactional
public interface DictionaryRepository extends CrudRepository<Dictionary, Long> {
}
和
@Repository
@Transactional
public interface WordPairRepository extends CrudRepository<WordPair, Long> {
}
创建的表格如下所示:
DICTIONARY
ID
COMMENT
NAME
WORDPAIR
ID
RATING
SEMANTICUNITONE
SEMANTICUNITTWO
DICTIONARY_ID
以下测试显示我可以在两个方向上进行更新。
Dictionary dictionary = makeDictionary("comment", "dictionary 1");
dictionary.setWordPairs(new ArrayList<WordPair>());
dictionary.getWordPairs().add(makeWordPair("George", "Unit 3", "Unit 4", 65));
dictionary.getWordPairs().add(makeWordPair("Greg", "Unit 2", "Unit 1", 25));
dictionaryRepository.save(dictionary);
dictionary = dictionaryRepository.findOne(1l);
assertEquals("dictionary 1", dictionary.getName());
WordPair wordPair = wordPairRepository.findOne(dictionary.getWordPairs().get(0).getId());
assertEquals("dictionary 1", wordPair.getDictionary().getName());
wordPair.getDictionary().setName("dictionary 2");
wordPairRepository.save(wordPair);
wordPair = wordPairRepository.findOne(dictionary.getWordPairs().get(0).getId());
assertEquals("dictionary 2", wordPair.getDictionary().getName());
dictionary = dictionaryRepository.findOne(1l);
assertEquals("dictionary 2", dictionary.getName());
答案 1 :(得分:-1)
首先,您可以从wordPairs字段中删除@ManyToOne
,您只需要在Dictory中定义关系。并添加@JoinColumn(name = "dict_id")
以告知wordPair
表中的列以供参考。
如果无法解决您的问题,则应检查wordPairs
dictory的数据,id
字段是否有值。
检查代码:
@Entity
public class Dictionary {
@Id
@GeneratedValue
private Long id;
private String name;
private String comment;
@OneToMany(mappedBy = "dictionary", cascade = CascadeType.All, fetch=FetchType.EAGER)
@JoinColumn(name = "dict_id")// the column name in WorPair table to refer Dictory.
private List<WordPair> wordPairs;