在 Spring-Hibernate 项目中初始化实体集合(POJO)的正确方法是什么?

发布于 2024-09-29 12:38:45 字数 620 浏览 3 评论 0原文

我有一个 POJO 类,比如 Foo,它有一组其他实体实例,比如 bar。 此外,此类项目还有标准杂项类:Foo 和 Bar 的 service 和 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在哪里初始化比较好? 哪些特定的集合和列表更适合此类目的? 我当前的实施存在哪些概念性问题,以及如何做得更好?

提前致谢。

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.

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.

 
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?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

高速公鹿 2024-10-06 12:38:46

在哪里初始化Foo的Set比较好?

大多数时候,我在声明集合时初始化它,这是 Hibernate 所推荐的。引用文档:

6.1。持久化集合

Hibernate 需要持久性
声明集合值字段
作为接口类型。例如:

公共类产品{
    私有字符串序列号;
    私有 Set 部分 = new HashSet();

    public Set getParts() { 返回零件; }
    void setParts(设置零件) { this.parts = parts; }
    公共字符串 getSerialNumber() { 返回序列号; }
    void setSerialNumber(String sn) { 序列号 = sn; }
}

实际的界面可能是
java.util.Set,
java.util.Collection,
java.util.Listjava.util.Map
java.util.SortedSet,
java.util.SortedMap 或任何你
就像(“任何你喜欢的东西”意味着你
必须编写一个实现

org.hibernate.usertype.UserCollectionType。)

注意实例变量是如何的
用实例初始化
哈希集。这是最好的方法
初始化集合值
新实例化的属性
(非持久)实例。当你
使实例持久化,通过
例如调用persist(),
Hibernate 实际上将取代
HashSet 具有以下实例
Hibernate自己的实现
设置

如果将其保留为 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 允许重复并引入位置索引。

我当前的实现存在哪些概念性问题,以及如何做得更好?

  1. 不会在 getter 中执行赋值操作。
    • 如果此时某个集合应该为 null,则让它为 null
  2. 我没有看到你们服务的附加值
    • 为什么不直接调用 foo.getBars()
    • 为什么要转换集合?

Where it is better to initialize Foo's Set?

Most of time, I initialize a collections when declaring it, which is what Hibernate recommends. Quoting the documentation:

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
of
org.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
calling persist() for example,
Hibernate will actually replace the
HashSet with an instance of
Hibernate's own implementation of
Set.

If leaving it null is part of your business, my suggestion would be to initialize it in a (common) link management methods:

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?

It all depends on the semantics you need. A Set doesn't allow duplicates, a List allows duplicates and introduces positional indexing.

What conceptual issues has my current implementation, and how to do better?

  1. I wouldn't perform an assignment in the getter.
    • If a collection is supposed to be null at that point, let it be null.
  2. I don't see the added value of your service
    • why not just calling foo.getBars()?
    • why converting the collection?
執念 2024-10-06 12:38:46

您的实体可以是带有 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)您可以在另一个层(也称为服务层)中管理事务。

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

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.

莫言歌 2024-10-06 12:38:46

我倾向于在服务层中初始化集合,并在其中保留事务处理。因此,我可以在 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

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):

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文