java 在 Spring-Hibernate 项目中初始化实体 (POJO) 集合的正确方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4050259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the correct way to initialize collection of an entity (POJO) in Spring-Hibernate project?
提问by edio
I have a POJO class, say Foo, which has a Set of other entity instances, say bars. Also there are standart misc classes for such project: service and dao for both Foo and Bar.
我有一个 POJO 类,比如 Foo,它有一组其他实体实例,比如 bar。对于此类项目,还有标准的杂项类:Foo 和 Bar 的 service 和 dao。
I want BarService to get the Set of Bar instances associated with some Foo. Now I have the following code, wich I believe is conceptually bad.
我希望 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 questions: Where it is better to initialize Foo's Set? What specific Sets and Lists are better for such purposes? What conceptual issues has my current implementation, and how to do better?
3问:Foo的Set初始化在哪里比较好?哪些特定的 Sets 和 Lists 更适合用于此类目的?我当前的实现有哪些概念性问题,以及如何做得更好?
Thanks in advance.
提前致谢。
回答by Pascal Thivent
Where it is better to initialize Foo's Set?
在哪里初始化 Foo 的 Set 比较好?
Most of time, I initialize a collections when declaring it, which is what Hibernate recommends. Quoting the documentation:
大多数时候,我在声明集合时初始化它,这是 Hibernate 推荐的。引用文档:
6.1. Persistent collections
Hibernate requires that persistent collection-valued fields be declared as an interface type. For example:
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; } }
The actual interface might be
java.util.Set
,java.util.Collection
,java.util.List
,java.util.Map
,java.util.SortedSet
,java.util.SortedMap
or anything you like ("anything you like" means you will have to write an implementation oforg.hibernate.usertype.UserCollectionType
.)Notice how the instance variable was initialized with an instance of
HashSet
. This is the best way to initialize collection valued properties of newly instantiated (non-persistent) instances. When you make the instance persistent, by callingpersist()
for example, Hibernate will actually replace theHashSet
with an instance of Hibernate's own implementation ofSet
.
6.1. 持久化集合
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
.
If leaving it null
is part of your business, my suggestion would be to initialize it in a (common) link management methods:
如果离开它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);
}
}
What specific Sets and Lists are better for such purposes?
哪些特定的 Sets 和 Lists 更适合用于此类目的?
It all depends on the semantics you need. A Set
doesn't allow duplicates, a List
allows duplicates and introduces positional indexing.
这一切都取决于您需要的语义。ASet
不允许重复,aList
允许重复并引入位置索引。
What conceptual issues has my current implementation, and how to do better?
我当前的实现有哪些概念性问题,以及如何做得更好?
- Iwouldn't perform an assignment in the getter.
- If a collection is supposed to be
null
at that point, let it benull
.
- If a collection is supposed to be
- I don't see the added value of your service
- why not just calling
foo.getBars()
? - why converting the collection?
- why not just calling
- 我不会在 getter 中执行任务。
- 如果一个集合应该
null
在那个时候,就让它成为null
。
- 如果一个集合应该
- 我看不到你们服务的附加价值
- 为什么不直接打电话
foo.getBars()
? - 为什么要转换集合?
- 为什么不直接打电话
回答by ch4nd4n
Your entity could be simple set of fields with getters and setters. What you need to take care of is how you relate your objects and approach you take to populate objects.
ORM APIs gives liberty of using Objects rather than SQL. You should be careful as to when you should choose to initialize the fields of an Object. For example if you have an object person, which comprises of name, age, collection of contacts and cities visited. In a situation where you are interested in name and age of the person and not contact and cities, you should load name and age only. Which implies that contacts and cities should be lazy loaded.
When interested in contact you load only contacts and not the entire person object or through person object. You would want to load Set of contacts only using Dao/Service and explicitly defining methods to load specific aspect of the object (use of reverse association).
Some best hibernate practices can be found at Best Practices.
Updated:
1) Entity does not populate on its own. One of the popular approach is to have DAO to do this Job. Your Entity could simple be
您的实体可以是带有 getter 和 setter 的简单字段集。您需要注意的是如何关联对象以及填充对象所采用的方法。
ORM API 提供了使用对象而不是 SQL 的自由。您应该注意何时选择初始化对象的字段。例如,如果您有一个对象人员,其中包括姓名、年龄、联系人集合和访问过的城市。如果您对人员的姓名和年龄而不是联系人和城市感兴趣,则应仅加载姓名和年龄。这意味着应该延迟加载联系人和城市。
当对联系人感兴趣时,您只加载联系人而不是整个人物对象或通过人物对象。您可能只想使用 Dao/Service 加载联系人集,并明确定义加载对象特定方面的方法(使用反向关联)。
一些最佳休眠实践可以在最佳实践中找到。更新:1) 实体不会自行填充。一种流行的方法是让 DAO 来完成这项工作。您的实体可能很简单
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) You can have transaction managed in another layer also referred as Service layer.
2)您可以在另一层(也称为服务层)中管理事务。
回答by fasseg
i tend to initialize the collections in the service layer where i keep the transaction handling as well. So i can have a method in my BaseDAO which lets me initialize any collection of any Entity in my projects using reflection, by passing the collection names into the method which are to be fetched eagerly (initialized):
我倾向于在服务层初始化集合,在那里我也保留事务处理。所以我可以在我的 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;
}
then you can initialize any collection from the service layer using this method:
然后您可以使用此方法从服务层初始化任何集合:
MyEntity ent=getEntity(MyEntity.class,id,new String[]{"collection1","collection2"});
A more detailed example: http://objecthunter.congrace.de/tinybo/blog/articles/69
一个更详细的例子:http: //objecthunter.congrace.de/tinybo/blog/articles/69