hibernate 批量提取到@ElementCollection

b1payxdu  于 2022-11-14  发布在  其他
关注(0)|答案(1)|浏览(221)

我有以下实体及其持久化集合

@Entity
@Table(name = "A")
public class A implements Identifiable<Long> {
   @Id
   private Long id;

    @ElementCollection
    @CollectionTable(name = "B", joinColumns = { @JoinColumn(name = "B_ID") })
    private Collection<B> bList;

    @ElementCollection
    @CollectionTable(name = "C", joinColumns = { @JoinColumn(name = "C_ID") })
    private Collection<C> cList;
}

在加载10k行A实体之后,我还想加载它的集合

// loading A entities
final List<A> aList = getA();
// looping from 10k results
for (final A a : aList) {
   final List<B> bList = a.getB();
   final List<C> cList = a.getC();
}

和SELECT语句生成了相当多(~10k)。
这里的表现很差!
有什么想法可以在这里使用批次选择吗?

mbjcgjjk

mbjcgjjk1#

我已经解决了这个问题!

想法

在使用@ElementCollection时,Hibernate将负责SQL语句和到实体列表值的Map。使用起来很舒服,但我们有一个折衷方案。我们得到的家长结果越多,我们的表现就越差。如果我们有10k个记录的父级,Hibernate会选择10k次来获取它的子级关系。
而不是为每个父对象加载子对象。创建本地查询以加载所有内容。
我们得到的结果如下:

PARENT_ID    CHILD_ID
1            1
1            2
1            3
2            1
2            2
3            3

然后实现Hibernate转换器将这些原始数据库对象转换为DTO。

代码示例。

创建DTO

public class ADto {
   private long id;
   private Collection<BDto> bList = new HashSet<>();
   
   // Constructor

   public void addChildren(BDto b) {
       bList.add(b);
   }

   //equals and hascode
}

public class BDto {
   private long id;
   
   // Constructor
   
   //equals and hascode
}

和变压器

public class CustomTransformer extends AliasedTupleSubsetResultTransformer {

     private final Map<Long, ADto> result = new HashMap<>();
     private final Map<String, Integer> aliasIndexes = new HashMap<>();

    @Override
    public List transformList(final List list) {
        return new ArrayList(new LinkedHashSet(list));
    }

    @Override
    public UsableCapacity transformTuple(final Object[] tuple, final String[] aliases) {
        init(aliases);
        final A aEntity = (A) get(tuple, "parent"); // same as alias in DAO layer
        final B bEntity = (B) get(tuple, "child");  // same as alias in DAO layer
        final Long id = aEntity.getId();
        final ADto aDto;
        if (result.containsKey(id)) {
            aDto = result.get(id);
        } else {
            aDto = new ADto(...);
        }
        aDto.addChildren(new BDto(...)); // create BDto instance from BEntity
        result.put(id, aDto);
        return aDto;
    }

    private Object get(final Object[] capacities, final String alias) {
        return capacities[aliasIndexes.get(alias)];
    }

    private void init(final String[] aliases) {
        if (aliasIndexes.isEmpty()) {
            for (int i = 0; i < aliases.length; i++) {
                final String alias = aliases[i];
                aliasIndexes.put(alias, i);
            }
        }
    }
}

DAO层

final String queryString = "SELECT {parent.*}, {child.*} FROM A parent LEFT JOIN B child ON parent.id = child.parent_id";
final NativeQuery query = getCurrentSession().createNativeQuery(queryString)
                                             .addEntity("parent", A.class)
                                             .addEntity("child", B.class);
// Todo
query.setResultTransformer(new CustomTransformer());
return safeList(query);

相关问题