绵阳做网站优化,游戏网站建站,网站推广对接,公司模板建站java联接pg库是否可以将联接的数据库表转换为Java Stream#xff1f; 答案是肯定的。 由于我们已经多次提出这个问题#xff0c;因此我们决定写另一篇动手实验文章#xff0c;说明如何执行更高级的Stream Joins。 因此#xff0c;这里是第六篇中的第五篇#xff0c;后面还… java联接pg库 是否可以将联接的数据库表转换为Java Stream 答案是肯定的。 由于我们已经多次提出这个问题因此我们决定写另一篇动手实验文章说明如何执行更高级的Stream Joins。 因此这里是第六篇中的第五篇后面还有一个GitHub存储库其中包含每个单元的说明和练习。 第1部分创建流 第2部分中级操作 第三部分终端操作 第4部分数据库流 第5部分将联接的数据库表转换为流 第6部分使用流创建数据库应用程序 流加入 在上一篇文章中我们指出了Streams和SQL构造之间的巨大相似之处。 虽然在一般情况下SQL操作JOIN缺少自然映射。 因此 Speedment利用自己的 JoinComponent以类型安全的方式联接最多10个表使用INNER JOINRIGHT JOINLEFT JOIN或CROSS JOIN。 在更深入地介绍JoinComponent之前我们将详细说明各个表与联接之间的相似性。 我们以前使用Speedment Manager作为数据库表的句柄。 此过程如下所示 管理器充当数据库表的句柄并且可以充当流源。 在这种情况下每一行都对应一个Film实例。 现在我们希望从多个表中检索数据仅凭Manager还是不够的。 SQL JOIN查询输出一个虚拟表该虚拟表以不同方式例如取决于联接类型和WHERE子句组合来自多个表的数据。 在Speedment中该虚拟表表示为JoinT对象该对象持有类型T元组。 连接组件 要检索Join对象我们需要前面提到的使用构建器模式的JoinComponent 。 产生的Join对象是可重用的并充当“虚拟联接表”的句柄如下图所示 JoinComponent创建一个Join对象该对象充当虚拟表的句柄联接的结果并且可以充当流源。 在这种情况下每一行都对应一个Tuple2的实例 现在我们已经介绍了JoinComponent的概念我们可以开始演示如何使用它。 多对一 我们从多对一关系开始其中第一张表中的多行可以与第二张表中的同一行匹配。 例如在许多电影中可以使用一种语言。 我们可以使用 JoinCompontent JoinTuple2Film, Language join joinComponent .from(FilmManager.IDENTIFIER) .innerJoinOn(Language.LANGUAGE_ID).equal(Film.LANGUAGE_ID) .build(Tuples::of); 基本上我们从Film表开始然后对Language表在具有匹配language_ids的行上执行INNER JOIN。 然后我们可以使用Join对象在生成的元组上流式传输并全部打印出来以供显示。 与Streams一样即使重复使用相同的join-Element也不能保证元素的特定顺序。 join.stream() .forEach(System.out::println); Tuple2Impl {FilmImpl { filmId 1 , title ACADEMY DINOSAUR, ... }, LanguageImpl { languageId 1 , name English, ... }} Tuple2Impl {FilmImpl { filmId 2 , title ACE GOLDFINGER, ... }, LanguageImpl { languageId 1 , name English, ... }} Tuple2Impl {FilmImpl { filmId 3 , title ADAPTATION HOLES, ... }, LanguageImpl { languageId 1 , name English, ... }} … 多对多 多对多关系定义为两个表之间的关系其中第一个表中的许多行可以匹配第二个表中的多个行。 通常使用第三张表来形成这些关系。 例如演员可以参加几部电影而一部电影中通常有几个演员。 Sakila中电影与演员之间的关系由 FilmActor表该表使用外键引用电影和演员。 因此如果我们想将每个Film条目与该电影的主演演员联系起来我们需要加入所有三个表 JoinTuple3FilmActor, Film, Actor join joinComponent .from(FilmActorManager.IDENTIFIER) .innerJoinOn(Film.FILM_ID).equal(FilmActor.FILM_ID) .innerJoinOn(Actor.ACTOR_ID).equal(FilmActor.ACTOR_ID) .build(Tuples::of); 我们从描述电影与演员之间的关系的表开始并分别在匹配FILM_IDs和ACTOR_IDs的情况下与Film和Actor进行表演和INNER JOIN。 收集加入流到地图 现在我们的Join对象可用于创建与 带有主演Actor List的Film s。 由于流中的元素是元组因此我们需要指向所需的条目。 这是使用零索引的吸气剂引用FilmActor get0()等完成的。 MapFilm, ListActor actorsInFilms join.stream() .collect( groupingBy(Tuple3::get1, mapping(Tuple3::get2, toList()) ) ); 最后我们打印条目以显示电影和演员的姓名。 actorsInFilms.forEach((f, al) - System.out.format( %s : %s%n , f.getTitle(), al.stream() .sorted(Actor.LAST_NAME) .map(a - a.getFirstName() a.getLastName()) .collect(joining( , ) ) ) ); WONDERLAND CHRISTMAS : HARRISON BALE, CHRIS BRIDGES, HUMPHREY GARLAND, WOODY JOLIE, CUBA OLIVIER BUBBLE GROSSE : VIVIEN BASINGER, ROCK DUKAKIS, MENA HOPPER OPUS ICE : DARYL CRAWFORD, JULIA FAWCETT, HUMPHREY GARLAND, SEAN WILLIAMS … 筛选表 如果我们最初知道我们只对 Film条目在定义Join摆脱这些实例会更有效。 这是使用.where运算符完成的该运算符等效于流上的filter() 并映射到SQL关键字WHERE。 作为过滤器它使用评估为true或false的Predicate 并应使用Speedment Fields进行表达以进行优化。 在这里我们要查找标题以“ A”开头的电影的语言 JoinTuple2Film, Language join joinComponent .from(FilmManager.IDENTIFIER) .where(Film.TITLE.startsWith(“A”)) .innerJoinOn(Language.LANGUAGE_ID).equal(Film.LANGUAGE_ID) .build(Tuples::of); 如果需要进一步过滤则可以将任意数量的.where操作与幕后SQL关键字AND组合在一起。 专业建筑商 Sofar我们不得不处理元组的相当抽象的getterget0get1等。 尽管在构建连接对象时我们可以为特殊对象提供任何构造函数。 在上面显示的示例中我们对电影的名称和演员的名字感兴趣。 这使我们可以定义自己的对象 TitleActorName final class TitleActorName { private final String title; private final String actorName; TitleActorName(Film film, Actor actor) { this .title film.getTitle(); this .actorName actor.getFirstName() actor.getLastName(); } public String title() { return title; } public String actorName() { return actorName; } Override public String toString() { return TitleLanguageName{ title title , actorName actorName } ; } } 然后我们将自己的对象的构造函数提供给Join构造函数并丢弃链接的FilmActor实例因为它未被使用 JoinTitleActorName join joinComponent .from(FilmActorManager.IDENTIFIER) .innerJoinOn(Film.FILM_ID).equal(FilmActor.FILM_ID) .innerJoinOn(Actor.ACTOR_ID).equal(FilmActor.ACTOR_ID) .build((fa, f, a) - new TitleActorName(f, a)); 这极大地提高了涉及所产生的Join对象的任何操作的可读性。 MapString, ListString actorsInFilms join.stream() .collect( groupingBy(TitleActorName::title, mapping(TitleActorName::actorName, toList()) ) ); actorsInFilms.forEach((f, al) - System.out.format( %s : %s%n , f, al) ); 简化类型 当连接大量表时编写Java类型可能很Tuple5... 例如Tuple5... 。 如果您使用Java的最新版本则可以像下面这样简单地忽略局部变量的类型 var join joinComponent .from(FilmManager.IDENTIFIER) .where(Film.TITLE.startsWith(“A”)) .innerJoinOn(Language.LANGUAGE_ID).equal(Film.LANGUAGE_ID) .build(Tuples::of); 在这种情况下Java将自动将类型推断为JoinTuple2Film, Language 如果使用的是较旧的Java版本则可以像这样内联连接声明和流运算符 joinComponent .from(FilmManager.IDENTIFIER) .where(Film.TITLE.startsWith(“A”)) .innerJoinOn(Language.LANGUAGE_ID).equal(Film.LANGUAGE_ID) .build(Tuples::of) .stream() .forEach(System.out::println); 练习题 本周的练习将需要先前所有单元的综合知识因此可以作为先前单元的重要后续课程。 云中仍存在到Sakila数据库实例的连接因此无需设置Speedment。 像往常一样这些练习可以在此GitHub存储库中找到。 本文的内容足以解决名为MyUnit5Extra的第五个单元。 相应的Unit5Extra接口包含JavaDocs它们描述了以下方法的预期实现。 MyUnit5Extra 。 public interface Unit5Extra { /** * Creates and returns a new Map with Actors as keys and * a List of Films in which they appear as values. * p * The result might look like this: * * ActorImpl { actorId 126, firstName FRANCES, lastName TOMEI, ... }[FilmImpl { filmId 21, title AMERICAN CIRCUS, ...}, ...] * … * * param joinComponent for data input * return a new Map with Actors as keys and * a List of Films in which they appear as values */ MapActor, ListFilm filmographies(JoinComponent joinComponent); 提供的测试例如Unit5ExtraTest 将充当自动评分工具让您知道您的解决方案是否正确。 下一篇 到目前为止我们希望能够设法证明Stream API对于数据库查询的整洁程度。 下一篇文章将超越电影租赁领域并允许您为任何数据源用纯Java编写独立的数据库应用程序。 编码愉快 s Per Minborg Julia·古斯塔夫森Julia Gustafsson 资源资源 GitHub开源项目加速 Speedment Stream ORM 初始化程序 GitHub存储库“ hol-streams” 文章第1部分创建流 第2部分中级操作 第3部分终端机操作 翻译自: https://www.javacodegeeks.com/2019/11/become-a-master-of-java-streams-part-5-turn-joined-database-tables-into-a-stream.htmljava联接pg库