我有一个POJO类,比如Foo,它有一组其他实体实例,比如说吧。 此类项目还有标准的misc类:Foo和Bar的服务和dao。
我希望BarService获取与某些Foo相关联的Bar实例集。现在我有以下代码,我相信它在概念上很糟糕。
public class Foo {
Set<Bar> bars;
public Set<Bar> getBars() {
if (bars == null)
return ( bars = new HashSet() );
return bars;
}
}
public class BarServiceImpl {
public List<Bar> getListOfBars(Foo foo) {
return new ArrayList(foo.getBars());
}
}
3个问题: 在哪里初始化Foo的Set更好? 哪些特定的集合和列表更适合此类目的? 我目前的实施有哪些概念性问题,以及如何做得更好?
提前致谢。
答案 0 :(得分:11)
最好初始化Foo的Set?
大多数时候,我在声明它时初始化集合,这是Hibernate推荐的。引用文档:
6.1. Persistent collections
Hibernate要求持久化 收集值字段被声明 作为接口类型。例如:
public class Product { private String serialNumber; private Set parts = new HashSet(); public Set getParts() { return parts; } void setParts(Set parts) { this.parts = parts; } public String getSerialNumber() { return serialNumber; } void setSerialNumber(String sn) { serialNumber = sn; } }
实际界面可能是
java.util.Set
,java.util.Collection
,java.util.List
,java.util.Map
,java.util.SortedSet
,java.util.SortedMap
或任何你 喜欢(“你喜欢的任何东西”意味着你 将不得不写一个实现 的org.hibernate.usertype.UserCollectionType
。)注意实例变量是怎样的 用一个实例初始化
HashSet
。这是最好的方法 初始化集合值 新实例化的属性 (非持久性)实例。当你 使实例持久化 以persist()
为例, Hibernate实际上会取代HashSet
,其实例为 Hibernate自己的实现Set
。
如果离开它null
是您业务的一部分,我的建议是用(常见)链接管理方法初始化它:
public class Foo {
...
private Set<Bar> bars;
...
public void addBar(Bar bar) {
if (this.bars == null) {
this.bars = new HashSet<Bar>();
}
this.bars.add(bar);
}
}
哪些特定的集合和列表更适合此类用途?
这一切都取决于你需要的语义。 Set
不允许重复,List
允许重复并引入位置索引。
我目前的实施有哪些概念性问题,以及如何做得更好?
null
,请将其设为null
。 foo.getBars()
?答案 1 :(得分:2)
您的实体可以是带有getter和setter的简单字段集。您需要注意的是如何将对象与填充对象的方法联系起来
ORM API提供了使用Objects而不是SQL的自由。您应该在何时选择初始化Object的字段时要小心。例如,如果您有一个对象人员,其中包括姓名,年龄,联系人集合和访问过的城市。如果您对此人的姓名和年龄感兴趣而不是联系方式和城市,则应仅加载姓名和年龄。这意味着联系人和城市应该是懒惰的
当您对联系感兴趣时,您只加载联系人而不是整个人物对象或通过人物对象。您只想使用Dao / Service加载一组联系人,并明确定义加载对象特定方面的方法(使用反向关联)。
一些最好的休眠实践可以在Best Practices找到。
更新:
1)实体不会自行填充。一种流行的方法是让DAO做这个Job。你的实体很简单
public class Foo {
private Set<Bar> bar=new HashSet<Bar>();
public Set<Bar> getBar {
return bar;
}
public void setBar(Bar bar) {
this.bar = bar;
}
}
2)您可以在另一个层中管理事务,也称为服务层。
答案 2 :(得分:1)
我倾向于初始化服务层中的集合,我也保持事务处理。所以我可以在我的BaseDAO中有一个方法,它允许我使用反射初始化我项目中任何实体的任何集合,方法是将集合名称传递给要急切获取的方法(初始化):
public <T extends Object> T getEntity(Class<T> clazz,long id,String[] collectionsToBeInitialized){
T entity=(T) this.getCurrentSession().createCriteria(clazz).add(Restrictions.idEq(id)).setFetchMode(collectionsToBeInitialized[0], FetchMode.JOIN).uniqueResult();
int length=collectionsToBeInitialized.length;
for (int idx=1;idx<length;idx++){
String collectionName=collectionsToBeInitialized[idx];
try {
Method m = clazz.getMethod("get" + collectionName.substring(0, 1).toUpperCase() + collectionName.substring(1),(Class<T>) null);
Hibernate.initialize(m.invoke(entity,(Object[]) null));
} catch (NoSuchMethodException e) {
LOG.error("Could not initialize collection " + collectionName + " of class Event", e);
} catch (InvocationTargetException e) {
LOG.error("Could not initialize collection " + collectionName + " of class Event", e);
} catch (IllegalAccessException e) {
LOG.error("Could not initialize collection " + collectionName + " of class Event", e);
}
}
return entity;
}
然后您可以使用此方法从服务层初始化任何集合:
MyEntity ent=getEntity(MyEntity.class,id,new String[]{"collection1","collection2"});
更详细的例子: http://objecthunter.congrace.de/tinybo/blog/articles/69