我的spring-mvc-hibernate应用程序有三个Pet
对象列表(pets
,cats
,dogs
),这些对象填充在模型中({{1}需要通过控制器(OwnerController.java)发送到视图(映射到/ owner url模式的jsp)。所有三个列表都应该从底层数据库中的相同Owner
表填充,pets
列表包括pets
表中的所有列表和pets
列表仅包括cats
表中猫的条目,pets
列表仅包括来自dogs
表的狗的条目。 问题是所有三个列表都填充了所有宠物,无论其类型如何。 我已通过System.out.println()命令确认 列表填充的问题发生在模型级别 。如何让pets
列表仅包含猫,cats
列表仅包含狗?
以下是模型的相关代码,Owner.java:
dogs
以下是来自控制器的相关代码,OwnerController.java:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
private Set<Pet> pets;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER)
private Set<Pet> cats;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER)
private Set<Pet> dogs;
protected void setPetsInternal(Set<Pet> pets) {this.pets = pets;}
// Call this from OwnerController before returning data to page.
public void parsePets() {
for (Pet pet : getPetsInternal()) {
if (pet.getType().getName().equals("cat")) {
cats.add(pet);
System.out.println(pet.getType().getName());
System.out.println("cats.size() is: "+cats.size());
System.out.println("added a cat to cats");
}
else if (pet.getType().getName().equals("dog")) {
dogs.add(pet);
System.out.println(pet.getType().getName());
System.out.println("dogs.size() is: "+dogs.size());
System.out.println("added a dog to dogs");
}
// add as many as you want
System.out.println("-----------------------------------------------------------");
}
}
public Set<Pet> getCats() {
System.out.println("about to return cats");
for (Pet cat : cats) {System.out.println("counting a "+cat.getType()+" in cats.");}
System.out.println("cats.size() is: "+cats.size());
return cats;
}
public Set<Pet> getDogs() {
System.out.println("about to return dogs");
for (Pet dog : cats) {System.out.println("counting a "+dog.getType()+" in dogs.");}
System.out.println("dogs.size() is: "+dogs.size());
return dogs;
}
protected Set<Pet> getPetsInternal() {
if (this.pets == null) {this.pets = new HashSet<Pet>();}
return this.pets;
}
public List<Pet> getPets() {
List<Pet> sortedPets = new ArrayList<Pet>(getPetsInternal());
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedPets);
}
这里是来自jsp视图的相关代码,请注意三个蒲公英数据表中的每一个都是相同的,除了每个数据表都用于单独的列表,宠物,猫或狗:
@RequestMapping(value = "/owners", method = RequestMethod.GET)
public String processFindForm(@RequestParam("ownerID") String ownerId, Owner owner, BindingResult result, Map<String, Object> model) {
Collection<Owner> results = this.clinicService.findOwnerByLastName("");
model.put("selections", results);
int ownrId = Integer.parseInt(ownerId);
Owner sel_owner = this.clinicService.findOwnerById(ownrId);
sel_owner.parsePets();
model.put("sel_owner",sel_owner);
return "owners/ownersList";
}
当我在猫和狗之前注释掉@OneToMany注释时,会抛出以下错误:
<datatables:table id="pets" data="${sel_owner.pets}" cdn="true" row="pet" theme="bootstrap2"
cssClass="table table-striped" paginate="false" info="false" filter="false"
cssStyle="width: 350px;" align="left" >
<datatables:column title="Name" cssStyle="width: 200px;" display="html">
<c:out value="${pet.name}"/>
</datatables:column>
<datatables:column title="BirthDate" cssStyle="width: 300px;" display="html">
<joda:format value="${pet.birthDate}" pattern="yyyy-MM-dd"/>
</datatables:column>
<datatables:column title="Type" cssStyle="width: 200px;" display="html">
<c:out value="${pet.type.name}"/>
</datatables:column>
</datatables:table>
<datatables:table id="cats" data="${sel_owner.cats}" cdn="true" row="cat" theme="bootstrap2"
cssClass="table table-striped" paginate="false" info="false" filter="false"
cssStyle="width: 350px;" align="left" >
<datatables:column title="Name" cssStyle="width: 200px;" display="html">
<c:out value="${cat.name}"/>
</datatables:column>
<datatables:column title="BirthDate" cssStyle="width: 300px;" display="html">
<joda:format value="${cat.birthDate}" pattern="yyyy-MM-dd"/>
</datatables:column>
<datatables:column title="Type" cssStyle="width: 200px;" display="html">
<c:out value="${cat.type.name}"/>
</datatables:column>
</datatables:table>
<datatables:table id="dogs" data="${sel_owner.dogs}" cdn="true" row="dog" theme="bootstrap2"
cssClass="table table-striped" paginate="false" info="false" filter="false"
cssStyle="width: 350px;" align="left" >
<datatables:column title="Name" cssStyle="width: 200px;" display="html">
<c:out value="${dog.name}"/>
</datatables:column>
<datatables:column title="BirthDate" cssStyle="width: 300px;" display="html">
<joda:format value="${dog.birthDate}" pattern="yyyy-MM-dd"/>
</datatables:column>
<datatables:column title="Type" cssStyle="width: 200px;" display="html">
<c:out value="${dog.type.name}"/>
</datatables:column>
</datatables:table>
请注意,Cat和Dog未定义为类,因为此时它们不存储与宠物不同的信息或方法,我想简化代码。我需要制作Cat课程和Dog课程吗?或者我可以解决这个问题,而无需单独的类?
我添加了@Transactional并在猫和狗的声明之前注释了// @ OneToMany(...),但在宠物声明之前留下了@OneToMany(...)注释。我还添加了
Caused by: org.hibernate.MappingException:
Could not determine type for:
java.util.Set, at table: owners, for columns: [org.hibernate.mapping.Column(cats)]
宣布猫和狗。但是,现在应用程序无法在我执行Run As时初始化...在eclipse中运行服务器:
= new HashSet<Pet>();
business-config.xml的代码can be read at this link.任何人都可以告诉我如何解决这个问题吗?
我可以通过注释掉更改消除错误消息并让应用程序运行,但是当我需要猫和狗时,我留下三个列表(宠物,猫,狗)相同的问题每个都是不同的宠物子集。下面是代码,它消除了错误消息,但创建了三个相同的列表,这些列表不应该相同:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name
'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0'
defined in class path resource [spring/business-config.xml]: Initialization of bean failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'entityManagerFactory' defined in class path resource
[spring/business-config.xml]: Invocation of init method failed;
nested exception is javax.persistence.PersistenceException:
[PersistenceUnit: petclinic] Unable to build EntityManagerFactory
答案 0 :(得分:0)
您需要删除猫狗的hibernate映射!仅通过hibernate将(内部)pets
列表映射到数据库。然后过滤猫狗(就像你已经做过的那样)。
我想添加宠物,然后确保将它们添加到(内部)pets
列表中。
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER)
private Set<Pet> pets;
/**
* Selection of cats from pets, it is a COPY!
* Lazy populated cache, set it to NULL for invalidation.
* The set itself is unmodifiable!
*/
@Transient
private Set<Pet> catsCache;
/** the same for dogs: @Transient private Set<Pet> dogsCache; */
public Set<Pet> getPets() {
return Collections.<Pet>unmodifiableCollection(this.pet);
}
public Set<Pet> getCats() {
if (this.catsCache == null) {
Set<Pet> catsSelection = new HashSet();
for (Pet pet : this.pets) {
//assume pet.type is an emum called PetType wiht an enumaration cat, if this does
//not exist, then use: if (pet.getType().getName().equals("cat"))
if (pet.getType() == PetType.cat)
catsSelection.add(pet);
}
this.catsCache = Collections.<Pet>unmodifiableCollection(catsSelection);
}
return this.catsCache;
}
public void addPet(Pet catOrDog) {
this.pets.add(catOrDog);
this.catsCache = null;
}
答案 1 :(得分:0)
如果你想坚持你的方法,请dogs
和cats
瞬态,以便JPA不会尝试映射字段或用实体填充它们:
@Transient
private Set<Pet> cats = new HashSet<Pet>();
@Transient
private Set<Pet> dogs = new HashSet<Pet>();
如果您想要实现Dog
和Cat
类来建立和继承关系,您可以按照我的tutorial进行操作。