如何使用Java集合来模拟SQL内部联接操作?
在数据库中,我有:
餐桌人
KEY NAME
11 Senor
other non-important entries...桌上的东西
KEY ITEM
AA Moustache
BB Sombrero
CC HotSauce
other non-important entries...表PersonToThing
PERSON_KEY THING_KEY HAS
11 AA Y
11 BB N
11 CC Y
other non-important entries...我想模仿SQL语句:
SELECT Person.NAME, Thing.ITEM, PersonToThing.HAS
FROM Person
INNER JOIN PersonToThing ON Person.KEY=PersonToThing.PERSON_PKEY
INNER JOIN Thing ON Thing.KEY=PersonToThing.THING_KEY
WHERE Person.NAME="Senor";它产生结果集:
NAME ITEM HAS
Senor Moustache Y
Senor Sombrero N
Senor HotSauce Y我想把每个表放在一个Java中。
我已经将表导出到INSERT TABLE语句中。
我将通过遍历INSERT TABLE语句来填充Maps。
不幸的是,运行关系数据库建模系统是不可能的。
我不明白的是如何组织集合或地图,以及如何将它们链接在一起以模拟内部连接操作?
提前感谢您的时间和您所能给予的任何帮助。
发布于 2018-12-03 17:41:37
在你的例子中,人和事物之间有一对多的关系。对我来说,从数据库的角度来考虑这种关系要比从Java/OOP的角度考虑这种关系要困难得多。
在DB中,将person表连接到thing表,以提供每个人拥有的东西的列表。
这可以作为一张东西的地图进入你的应用程序,每一张都有拥有每一件东西的人的列表,或者作为一张人的地图,每一张都有他们拥有的东西的列表。
所以,在Java中,您本质上是在询问如何对其建模:
public class Person() {
private List<Thing> things;
}
...
public class SomeClass() {
private List<Person> peopleWithThings;
} 海事组织,你可以用两种方法-
使用multimap,您可以得到如下内容:
String key = "Senor";
Multimap<String, Thing> map = ArrayListMultimap.create();
map.put(key, thing1);
map.put(key, thing2);
assertEquals(2, map.size());发布于 2018-12-03 17:51:57
在集合论中,内连接本质上是一个交操作。Java集合没有内置的完全相同的集合论函数,但是对于联合(addAll)和交集(retainAll),它们确实有类似的函数。有关如何使用Set或其他集合实现内部连接/交叉的更多详细信息,请参见这个问题。
使用集合论的主要挑战是存在三种不同的对象类型,没有一种是相互继承的,在适当的关系模型中可能会出现这种情况。例如,如果Person和Thing都继承自PersonToThing作为父类,那么它将大大简化事情:
class Person extends PersonToThing {
// ...
}
class Thing extends PersonToThing {
// ...
}
class PersonToThing {
// now Person_Key and Thing_Key can be inherited
String personKey;
String thingKey;
// etc...
}使用这个模型,我们现在可以拥有一个PersonToThing对象的集合,并正确地说明一对多的关系:
Set<PersonToThing> people = selectAllFrom("Person");
Set<PersonToThing> thing = selectAllFrom("Thing");
Set<PersonToThing> innerJoin = people;
people.addAll(thing);
innerJoin.retainAll(thing);如果您重写对象的equals()函数来检查您的密钥,您可以执行任何您喜欢的连接,包括Senor过滤器,或者添加一个实用程序函数,使它成为一个更可重用和更友好的设计:
@Override
public boolean equals(Object personToThing) {
if (personToThing.getPersonKey() != null) {
return personKey.equals(personToThing.getPersonKey());
else
return thingKey.equals(personToThing.getThingKey());
}这是因为Set使用equals()来检查两个对象是否相同。这样,当它这样做时,我们就像连接一样比较键。
我保留了selectAllFrom()函数抽象的细节,因为您没有提供任何特定于数据库的样板代码,但是无论您需要怎样实现它都应该相当简单。
发布于 2018-12-03 18:54:05
嗯,这似乎不容易,但这是可能的。
首先进行一些准备--为了使用简单的注释生成getter/setter和构造函数,我使用Lombok项目,只需创建一个Maven项目并将这个依赖项添加到其中:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>下面是具有数据的类和表的定义:
@AllArgsConstructor @Getter
public static class Person {
private String key, name;
}
@AllArgsConstructor @Getter
public static class Thing {
private String key, item;
}
@AllArgsConstructor @Getter
public static class PersonToThing {
private String personKey, thingKey, has;
}
static Collection<Person> tablePerson = Arrays.asList(
new Person("11", "Senor"),
new Person("22", "Tom"));
static Collection<Thing> tableThing = Arrays.asList(
new Thing("AA", "Moustache"),
new Thing("BB", "Sombrero"),
new Thing("CC", "HotSauce"),
new Thing("XX", "Not important")
);
static Collection<PersonToThing> tablePerson2Thing = Arrays.asList(
new PersonToThing("11", "AA","Y"),
new PersonToThing("11", "BB","N"),
new PersonToThing("11", "CC","Y"));现在,对这三个集合执行连接的一段代码。
@AllArgsConstructor(staticName = "of") @Getter
public static class Tuple<V1,V2>{
private V1 v1;
private V2 v2;
}
@AllArgsConstructor(staticName = "of") @Getter
public static class Triple<V1,V2,V3>{
private V1 v1;
private V2 v2;
private V3 v3;
}
public static void main(String[] args) {
tablePerson.stream()
// WHERE Person.NAME="Senor";
.filter(x->x.getName()=="Senor")
// INNER JOIN PersonToThing
.flatMap( p -> tablePerson2Thing.stream()
.map(p2t-> Tuple.of(p,p2t))
// ON Person.KEY=PersonToThing.PERSON_PKEY
.filter(t->t.getV1().getKey()==t.getV2().getPersonKey())
)
// INNER JOIN Thing
.flatMap( p2t-> tableThing.stream()
.map(t-> Triple.of(p2t.getV1(),p2t.getV2(),t))
// ON Thing.KEY=PersonToThing.THING_KEY
.filter(t->t.getV2().getThingKey()==t.getV3().getKey())
)
// SELECT Person.NAME, Thing.ITEM, PersonToThing.HAS
.forEach(x->System.out.println(x.getV1().getName()+ " / " + x.getV3().getItem() + " / " + x.getV2().getHas()));
}其结果是:
Senor / Moustache / Y
Senor / Sombrero / N
Senor / HotSauce / Yhttps://stackoverflow.com/questions/53598249
复制相似问题