FunDA(1)- Query Result Row:强类型Query结果行

2024-04-09 04:58
文章标签 类型 row query result funda

本文主要是介绍FunDA(1)- Query Result Row:强类型Query结果行,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    FunDA的特点之一是以数据流方式提供逐行数据操作支持。这项功能解决了FRM如Slick数据操作以SQL批次模式为主所产生的问题。为了实现安全高效的数据行操作,我们必须把FRM产生的Query结果集转变成一种强类型的结果集,也就是可以字段名称进行操作的数据行类型结果集。在前面的一篇讨论中我们介绍了通过Shape来改变Slick Query结果行类型。不过这样的转变方式需要编程人员对Slick有较深的了解。更重要的是这种方式太依赖Slick的内部功能了。我们希望FunDA可以支持多种FRM,所以应当尽量避免与任何FRM的紧密耦合。看来从FRM的返回结果开始进行数据行类型格式转换是一种比较现实的选择。一般来说我们还是可以假定任何FRM的使用者对于FRM的Query结果集类型是能理解的,因为他们的主要目的就是为了使用这个结果集。那么由FunDA的使用者提供一个Query结果数据行与另一种类型的类型转换函数应该不算是什么太高的要求吧。FunDA的设计思路是由用户提供一个目标类型以及FRM Query结果数据行到这个强类型行类型的类型转换函数后由FunDA提供强类型行结果集。下面先看一个典型的Slick Query例子:

import slick.driver.H2Driver.api._
import scala.concurrent.duration._
import scala.concurrent.Awaitobject TypedRow extends App {class AlbumsTable(tag: Tag) extends Table[(Long,String,String,Option[Int],Int)](tag,"ALBUMS") {def id = column[Long]("ID",O.PrimaryKey)def title = column[String]("TITLE")def artist = column[String]("ARTIST")def year = column[Option[Int]]("YEAR")def company = column[Int]("COMPANY")def * = (id,title,artist,year,company)}val albums = TableQuery[AlbumsTable]class CompanyTable(tag: Tag) extends Table[(Int,String)](tag,"COMPANY") {def id = column[Int]("ID",O.PrimaryKey)def name = column[String]("NAME")def * = (id, name)}val companies = TableQuery[CompanyTable]val albumInfo = for {a <- albumsc <- companiesif (a.company === c.id)} yield(a.title,a.artist,a.year,c.name)val db = Database.forConfig("h2db")Await.result(db.run(albumInfo.result),Duration.Inf).foreach {r =>println(s"${r._1} by ${r._2}, ${r._3.getOrElse(2000)} ${r._4}")}}


上面例子里的albumInfo返回结果行类型是个Tuple类型:(String,String,Option[Int],Int),没有字段名的,所以只能用r._1,r._2...这样的位置注明方式来选择字段。用这种形式来使用返回结果很容易造成混乱,选用字段错误。

前面提到:如果用户能提供一个返回行类型和一个转换函数如下:

  case class AlbumRow(title: String,artist: String,year: Int,studio: String)def toTypedRow(raw: (String,String,Option[Int],String)):AlbumRow =AlbumRow(raw._1,raw._2,raw._3.getOrElse(2000),raw._4)

我们可以在读取数据后用这个函数来转换行类型:

  Await.result(db.run(albumInfo.result),Duration.Inf).map{raw =>toTypedRow(raw)}.foreach {r =>println(s"${r.title} by ${r.artist}, ${r.year} ${r.studio}")}


返回行类型AlbumRow是个强类型。现在我吗可以用字段名来选择数据字段值了。不过,还是有些地方不对劲:应该是用户提供了目标行类型和转换函数后,直接调用一个函数就可以得到需要的结果集了。是的,我们就是要设计一套后台工具库来提供这个函数。

下面我们要设计FunDA的数据行类型class FDADataRow。这个类型现在基本上完全是针对Slick而设的,成功完成功能实现后期再考虑松散耦合问题。这个类型需要一个目标行类型定义和一个类型转换函数,外加一些Slick profile, database等信息。然后提供一个目标行类型结果集函数getTypedRows:

package com.bayakala.funda.rowtypesimport scala.concurrent.duration._
import scala.concurrent.Await
import slick.driver.JdbcProfileobject DataRowType {class FDADataRow[SOURCE, TARGET](slickProfile: JdbcProfile,convert: SOURCE  => TARGET){import slickProfile.api._def getTypedRows(slickAction: DBIO[Iterable[SOURCE]])(slickDB: Database): Iterable[TARGET] =Await.result(slickDB.run(slickAction), Duration.Inf).map(raw => convert(raw))}object FDADataRow {def apply[SOURCE, TARGET](slickProfile: JdbcProfile, converter: SOURCE => TARGET): FDADataRow[SOURCE, TARGET] =new FDADataRow[SOURCE, TARGET](slickProfile, converter)}}


下面是这个函数库的使用示范:

  import com.bayakala.funda.rowtypes.DataRowTypeval loader = FDADataRow(slick.driver.H2Driver, toTypedRow _)loader.getTypedRows(albumInfo.result)(db).foreach {r =>println(s"${r.title} by ${r.artist}, ${r.year} ${r.studio}")}


那么,作为一种数据行,又如何进行数据字段的更新呢?我们应该把它当作immutable object用函数式方法更新:

  def updateYear(from: AlbumRow): AlbumRow =AlbumRow(from.title,from.artist,from.year+1,from.studio)loader.getTypedRows(albumInfo.result)(db).map(updateYear).foreach {r =>println(s"${r.title} by ${r.artist}, ${r.year} ${r.studio}")}


updateYear是个典型的函数式方法:传入AlbumRow,返回新的AlbumRow。

下面是这篇讨论中的源代码:

FunDA函数库:

package com.bayakala.funda.rowtypesimport scala.concurrent.duration._
import scala.concurrent.Await
import slick.driver.JdbcProfileobject DataRowType {class FDADataRow[SOURCE, TARGET](slickProfile: JdbcProfile,convert: SOURCE  => TARGET){import slickProfile.api._def getTypedRows(slickAction: DBIO[Iterable[SOURCE]])(slickDB: Database): Iterable[TARGET] =Await.result(slickDB.run(slickAction), Duration.Inf).map(raw => convert(raw))}object FDADataRow {def apply[SOURCE, TARGET](slickProfile: JdbcProfile, converter: SOURCE => TARGET): FDADataRow[SOURCE, TARGET] =new FDADataRow[SOURCE, TARGET](slickProfile, converter)}}


功能测试源代码:

import slick.driver.H2Driver.api._import scala.concurrent.duration._
import scala.concurrent.Awaitobject TypedRow extends App {class AlbumsTable(tag: Tag) extends Table[(Long,String,String,Option[Int],Int)](tag,"ALBUMS") {def id = column[Long]("ID",O.PrimaryKey)def title = column[String]("TITLE")def artist = column[String]("ARTIST")def year = column[Option[Int]]("YEAR")def company = column[Int]("COMPANY")def * = (id,title,artist,year,company)}val albums = TableQuery[AlbumsTable]class CompanyTable(tag: Tag) extends Table[(Int,String)](tag,"COMPANY") {def id = column[Int]("ID",O.PrimaryKey)def name = column[String]("NAME")def * = (id, name)}val companies = TableQuery[CompanyTable]val albumInfo =for {a <- albumsc <- companiesif (a.company === c.id)} yield(a.title,a.artist,a.year,c.name)val db = Database.forConfig("h2db")Await.result(db.run(albumInfo.result),Duration.Inf).foreach {r =>println(s"${r._1} by ${r._2}, ${r._3.getOrElse(2000)} ${r._4}")}case class AlbumRow(title: String,artist: String,year: Int,studio: String)def toTypedRow(raw: (String,String,Option[Int],String)):AlbumRow =AlbumRow(raw._1,raw._2,raw._3.getOrElse(2000),raw._4)Await.result(db.run(albumInfo.result),Duration.Inf).map{raw =>toTypedRow(raw)}.foreach {r =>println(s"${r.title} by ${r.artist}, ${r.year} ${r.studio}")}import com.bayakala.funda.rowtypes.DataRowType.FDADataRowval loader = FDADataRow(slick.driver.H2Driver, toTypedRow _)loader.getTypedRows(albumInfo.result)(db).foreach {r =>println(s"${r.title} by ${r.artist}, ${r.year} ${r.studio}")}def updateYear(from: AlbumRow): AlbumRow =AlbumRow(from.title,from.artist,from.year+1,from.studio)loader.getTypedRows(albumInfo.result)(db).map(updateYear).foreach {r =>println(s"${r.title} by ${r.artist}, ${r.year} ${r.studio}")}}












这篇关于FunDA(1)- Query Result Row:强类型Query结果行的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/887230

相关文章

Python容器类型之列表/字典/元组/集合方式

《Python容器类型之列表/字典/元组/集合方式》:本文主要介绍Python容器类型之列表/字典/元组/集合方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 列表(List) - 有序可变序列1.1 基本特性1.2 核心操作1.3 应用场景2. 字典(D

Python如何在Word中生成多种不同类型的图表

《Python如何在Word中生成多种不同类型的图表》Word文档中插入图表不仅能直观呈现数据,还能提升文档的可读性和专业性,本文将介绍如何使用Python在Word文档中创建和自定义各种图表,需要的... 目录在Word中创建柱形图在Word中创建条形图在Word中创建折线图在Word中创建饼图在Word

SpringBoot接收JSON类型的参数方式

《SpringBoot接收JSON类型的参数方式》:本文主要介绍SpringBoot接收JSON类型的参数方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、jsON二、代码准备三、Apifox操作总结一、JSON在学习前端技术时,我们有讲到过JSON,而在

Rust中的BoxT之堆上的数据与递归类型详解

《Rust中的BoxT之堆上的数据与递归类型详解》本文介绍了Rust中的BoxT类型,包括其在堆与栈之间的内存分配,性能优势,以及如何利用BoxT来实现递归类型和处理大小未知类型,通过BoxT,Rus... 目录1. Box<T> 的基础知识1.1 堆与栈的分工1.2 性能优势2.1 递归类型的问题2.2

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

Mysql 中的多表连接和连接类型详解

《Mysql中的多表连接和连接类型详解》这篇文章详细介绍了MySQL中的多表连接及其各种类型,包括内连接、左连接、右连接、全外连接、自连接和交叉连接,通过这些连接方式,可以将分散在不同表中的相关数据... 目录什么是多表连接?1. 内连接(INNER JOIN)2. 左连接(LEFT JOIN 或 LEFT