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中Json和其他类型相互转换的实现示例

《Python中Json和其他类型相互转换的实现示例》本文介绍了在Python中使用json模块实现json数据与dict、object之间的高效转换,包括loads(),load(),dumps()... 项目中经常会用到json格式转为object对象、dict字典格式等。在此做个记录,方便后续用到该方

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

《MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)》本文给大家介绍MyBatis的xml中字符串类型判空与非字符串类型判空处理方式,本文给大家介绍的非常详细,对大家的学习或... 目录完整 Hutool 写法版本对比优化为什么status变成Long?为什么 price 没事?怎

C#之枚举类型与随机数详解

《C#之枚举类型与随机数详解》文章讲解了枚举类型的定义与使用方法,包括在main外部声明枚举,用于表示游戏状态和周几状态,枚举值默认从0开始递增,也可手动设置初始值以生成随机数... 目录枚举类型1.定义枚举类型(main外)2.使用生成随机数总结枚举类型1.定义枚举类型(main外)enum 类型名字

Python lambda函数(匿名函数)、参数类型与递归全解析

《Pythonlambda函数(匿名函数)、参数类型与递归全解析》本文详解Python中lambda匿名函数、灵活参数类型和递归函数三大进阶特性,分别介绍其定义、应用场景及注意事项,助力编写简洁高效... 目录一、lambda 匿名函数:简洁的单行函数1. lambda 的定义与基本用法2. lambda

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

MySQL 索引简介及常见的索引类型有哪些

《MySQL索引简介及常见的索引类型有哪些》MySQL索引是加速数据检索的特殊结构,用于存储列值与位置信息,常见的索引类型包括:主键索引、唯一索引、普通索引、复合索引、全文索引和空间索引等,本文介绍... 目录什么是 mysql 的索引?常见的索引类型有哪些?总结性回答详细解释1. MySQL 索引的概念2

Java获取当前时间String类型和Date类型方式

《Java获取当前时间String类型和Date类型方式》:本文主要介绍Java获取当前时间String类型和Date类型方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录Java获取当前时间String和Date类型String类型和Date类型输出结果总结Java获取

SpringBoot改造MCP服务器的详细说明(StreamableHTTP 类型)

《SpringBoot改造MCP服务器的详细说明(StreamableHTTP类型)》本文介绍了SpringBoot如何实现MCPStreamableHTTP服务器,并且使用CherryStudio... 目录SpringBoot改造MCP服务器(StreamableHTTP)1 项目说明2 使用说明2.1