在我的项目中,我有两个实体:Race
和RaceDriver
,其中包含Race
:
class RaceDriver {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "race", nullable = false)
private Race race;
...
@Column(name = "starting_nr")
private Integer startingNr;
...
@Column(name = "disqualified", nullable = false)
private boolean disqualified;
}
现在,我想要的是在startingNr
中获取disqualified
RaceDriver
的{{1}}列表,如下所示:
Race
问题是,现在我需要相同,但为少数 public List<Integer> findDisqualifiedDriversStartingNumbers(Integer raceId) {
ProjectionList projection = Projections.projectionList()
.add(Projections.property("startingNr").as("startingNr"));
return getSession()
.createCriteria(RaceDriver.class)
.setProjection(projection)
.add(Restrictions.eq("race.id", raceId))
.add(Restrictions.eq("disqualified", true))
.list();
}
。如何在不进行单独DAO调用的情况下实现此目的?因为我听说在单个数据库调用中尽可能做得更好。
我的想法是简单地获取在给定种族中被取消资格的驱动程序列表,然后在Java代码中解析它,我认为这将需要很少的循环,并制作一些不合格的Races
地图的起始数字,密钥为RaceDriver
。
DAO尝试看起来像这样:
Race.id
问题是我会得到那些大对象,而不是我需要的唯一数据的地图或列表(public List<RaceDriver> findDisqualifiedDriversInRaces(List<Integer> raceIds) {
return getSession()
.createCriteria(RaceDriver.class)
.add(Restrictions.in("race.id", raceIds))
.add(Restrictions.eq("disqualified", true))
.list();
}
和startingNr
)。
所以问题是 - 我能以某种方式只使用Hibernate吗?
答案 0 :(得分:2)
您需要使用具有两个WHERE条件的hibernate创建Query
。
@PersistenceContext protected EntityManager em;
List<Integer> raceIds = Arrays.asList(1, 2, 3);
Query query = em.createQuery("FROM RaceDriver r WHERE r.raceId IN (:raceIds) AND r.disqualified = true");
query.setParameter("raceIds", raceIds);
List<RaceDriver> drivers = query.getResultList();
这将返回您提供的raceIds中的不合格驱动程序列表。
<强>更新强>
获得List<RaceDriver>
后,您可以循环播放drivers
,并以raceId
作为关键字生成HashMaps列表,并将startingNr
列表(不合格的驱动程序)列为价值。
HashMap<Integer,List<Integer>> startingNrHashMap=new...;
for(RaceDriver driver:drivers)
{
List<Integer> strNr = new ArrayList<Integer>();
if(startingNrHashMap.containsKey(driver.race.raceid))
{
//if race id is already present in hash map then
strNr = startingNrHashMap.get(driver.race.raceid);
strNr.add(driver.startingNr);
startingNrHashMap.put(driver.race.raceid,strNr);
}
else
{
// if race id is NOT present in hash map
strNr.add(driver.startingNr);
startingNrHashMap.put(driver.race.raceid,strNr);
}
strNr =null;
}
答案 1 :(得分:2)
我个人会在普通的java中使用这个解决方案,因为对于任何支持你的代码的开发人员来说,它会更清楚。
回答这个问题“可以通过Hibernate完成吗?”:是的,可能是ResultTransformer是正确的方式,特别是如果你的程序中需要多次进行地图转换。没有标准的变压器可以满足您的需求,但您可以编写自己的变压器:
public class MapOfListsResultTransformer<K, V> extends BasicTransformerAdapter {
public List transformList(List collection) {
final Map<K, List<V>> map = new HashMap<>();
for (Object object : collection) {
final Object[] objects = (Object[]) object;
final K key = (K) objects[0];
final V value = (V) objects[1];
if (!map.containsKey(key)) {
final List<V> list = new ArrayList<V>();
list.add(value);
map.put(key, list);
} else {
map.get(key).add(value);
}
}
return Arrays.asList(map);
}
}
它的用法如下:
public Map<Integer, List<Integer>> findDisqualifiedDriversInRaces(List<Integer> raceIds) {
ProjectionList projection = Projections.projectionList()
.add(Projections.property("race.id").as("race.id"))
.add(Projections.property("startingNr").as("startingNr"));
return (Map<Integer, List<Integer>>) getSession()
.createCriteria(RaceDriver.class)
.setProjection(projection)
.add(Restrictions.in("race.id", raceIds))
.add(Restrictions.eq("disqualified", true))
.setResultTransformer(new MapOfListsResultTransformer<Integer, Integer>())
.uniqueResult();
}
答案 2 :(得分:1)
我就这样做了:
public List<RaceDriver> findDisqualifiedDriversInRaces(List<Integer> raceIds) {
if (!raceIds.isEmpty()) { // it will crash if the list will have no elements!
return getSession()
.createCriteria(RaceDriver.class)
.add(Restrictions.in("race.id", raceIds))
.add(Restrictions.eq("disqualified", true))
.list();
}
return Collections.emptyList();
}
然后从中提取我想要的东西,我创建了一个辅助方法:
// key = race.id, value = list of disqualified raceDrivers' starting numbers
private HashMap<Integer, List<Integer>> extractStartingNumbersToMap(List<RaceDriver> disqualifiedDrivers) {
HashMap<Integer, List<Integer>> disqualifiedDriversMap = new HashMap<>();
for (RaceDriver raceDriver : disqualifiedDrivers) {
Integer raceId = raceDriver.getRace().getId();
if (!disqualifiedDriversMap.containsKey(raceId)) {
disqualifiedDriversMap.put(raceId, new ArrayList<>(Arrays.asList(raceDriver.getStartingNr())));
} else {
disqualifiedDriversMap.get(raceId).add(raceDriver.getStartingNr());
}
}
return disqualifiedDriversMap;
}
我在Mark T回答之前做过,因为你可以看到它非常相似。但是我发布它,因为它可能对某人有帮助。
答案 3 :(得分:0)
我问了同样的问题,它关于NHibernate和.NET MVC,但你可以了解DAO和ResultTransformer