Slick 數(shù)據(jù)庫(kù) Schema

2018-09-28 18:11 更新

數(shù)據(jù)庫(kù) Schema

我們之前 Slick 編程(2): 準(zhǔn)備開發(fā)環(huán)境使用自動(dòng)代碼生成工具生成數(shù)據(jù)庫(kù)表的 Slick 定義(使用 Lifted Embedding API ),本篇介紹如何手工來(lái)寫這些 Schema 定義。

數(shù)據(jù)庫(kù)表 Tables

為了能夠使用 Slick 的 Lifted Embedding API 定義類型安全的查詢,首先我們需要定義數(shù)據(jù)庫(kù)表代表表中每行數(shù)據(jù)的類和對(duì)應(yīng)于數(shù)據(jù)庫(kù)表的 Schema 的 TableQuery 值,我們先看看自動(dòng)生成的 Album 表個(gè)相關(guān)定義:

/** Entity class storing rows of table Album
   *  @param albumid Database column AlbumId PrimaryKey
   *  @param title Database column Title 
   *  @param artistid Database column ArtistId  */
  case class AlbumRow(albumid: Int, title: String, artistid: Int)
  /** GetResult implicit for fetching AlbumRow objects using plain SQL queries */
  implicit def GetResultAlbumRow(implicit e0: GR[Int], e1: GR[String]): GR[AlbumRow] = GR{
    prs => import prs._
    AlbumRow.tupled((<<[Int], <<[String], <<[Int]))
  }
  /** Table description of table Album. Objects of this class serve as prototypes for rows in queries. */
  class Album(tag: Tag) extends Table[AlbumRow](tag, "Album") {
    def * = (albumid, title, artistid) <> (AlbumRow.tupled, AlbumRow.unapply)
    /** Maps whole row to an option. Useful for outer joins. */
    def ? = (albumid.?, title.?, artistid.?).shaped.<>(
        {r=>import r._; _1.map(_=> AlbumRow.tupled((_1.get, _2.get, _3.get)))}, 
        (_:Any) =>  throw new Exception("Inserting into ? projection not supported."))

    /** Database column AlbumId PrimaryKey */
    val albumid: Column[Int] = column[Int]("AlbumId", O.PrimaryKey)
    /** Database column Title  */
    val title: Column[String] = column[String]("Title")
    /** Database column ArtistId  */
    val artistid: Column[Int] = column[Int]("ArtistId")

    /** Foreign key referencing Artist (database name FK_AlbumArtistId) */
    lazy val artistFk = foreignKey("FK_AlbumArtistId", artistid, Artist)
        (r => r.artistid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
  }
  /** Collection-like TableQuery object for table Album */
  lazy val Album = new TableQuery(tag => new Album(tag))

所有的字段(Column)使用 column 方法來(lái)定義,每個(gè)字段對(duì)應(yīng)一個(gè) Scala 類型和一個(gè)字段名稱(對(duì)應(yīng)到數(shù)據(jù)庫(kù)表的定義),下面為 Slick 支持的基本數(shù)據(jù)類型:

  • Numeric types: Byte, Short, Int, Long, BigDecimal, Float, Double
  • LOB types: java.sql.Blob, java.sql.Clob, Array[Byte]
  • Date types: java.sql.Date, java.sql.Time, java.sql.Timestamp
  • Boolean
  • String
  • Unit
  • java.util.UUID

支持 Null 的字段使用 Option[T] 來(lái)表示,其中 T 為上述基本數(shù)據(jù)類型,在字段名稱之后,你可以使用一些可選的字段定義,這些可選定義定義在 table 的 O 對(duì)象中。下面為常用的定義

PrimaryKey 表明該字段為主鍵Default[T](defaultValue: T) 該字段缺省值DBType(dbType: String) 非標(biāo)準(zhǔn)字段類型,比如 DBType(“VARCHAR(20)”) 做為 String 類型AutoInc 自動(dòng)增一的字段NotNull,Nullable 表明該字段是否可以為空

每個(gè)表定義都需要一個(gè)""方法定義了缺省映射,這定義了執(zhí)行查詢返回表格一行時(shí)的數(shù)據(jù)類型,Slick 的””不要求和數(shù)據(jù)庫(kù)表的定義一一映射,你可以添加字段(復(fù)合字段)或者省略掉某個(gè)字段。

匹配過(guò)的表定義

可以使用自定義的數(shù)據(jù)類型做為”*”的映射,這可以使用雙向映射操作符”“來(lái)完成。

比如:

def * = (albumid, title, artistid) <> (AlbumRow.tupled, AlbumRow.unapply)

約束

外鍵約束可以使用foreignKey來(lái)定義

/** Foreign key referencing Artist (database name FK_AlbumArtistId) */
    lazy val artistFk = foreignKey("FK_AlbumArtistId", artistid, Artist)
        (r => r.artistid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)

它的參數(shù)為外鍵約束的名稱,本表字段名稱,外鍵所在表名稱,和一個(gè)函數(shù),這個(gè)函數(shù)定義了外鍵約束,以及更新和刪除外鍵時(shí)的行為)

主鍵約束可以使用 primaryKey 來(lái)定義,這主要用作定義復(fù)合主鍵的情況

/** Primary key of Playlisttrack (database name PlaylistTrack_PK) */
    val pk = primaryKey("PlaylistTrack_PK", (playlistid, trackid))

其它比如索引的情況和主鍵約束非常類似,比如:

class A(tag: Tag) extends Table[(Int, Int)](tag, "a") {
    def k1 = column[Int]("k1")
    def k2 = column[Int]("k2")
    def * = (k1, k2)
    def idx = index("idx_a", (k1, k2), unique = true)
    // compiles to SQL:
    //   create unique index "idx_a" on "a" ("k1","k2")
}

數(shù)據(jù)庫(kù)定義語(yǔ)言 DDL

數(shù)據(jù)庫(kù)定義語(yǔ)句可以使用 TableQuery 的 ddl 方法,多個(gè) DDL 對(duì)象可以使用 ++ 連接,比如:

val ddl = coffees.ddl ++ suppliers.ddl
db withDynSession {
    ddl.create
    //...
    ddl.drop
}

ddl.create 和 ddl.drop 可以創(chuàng)建表和刪除表,如果需要看看對(duì)應(yīng)的 SQL 語(yǔ)句,可以使用

val ddl = Album.ddl
ddl.createStatements.foreach(println)
ddl.dropStatements.foreach(println)

對(duì)應(yīng)的 MySQL 語(yǔ)句為

create table `Album` (`AlbumId` INTEGER NOT NULL PRIMARY KEY,`Title` VARCHAR(254) NOT NULL,`ArtistId` INTEGER NOT NULL)
alter table `Album` add constraint `FK_AlbumArtistId` foreign key(`ArtistId`) references `Artist`(`ArtistId`) on update NO ACTION on delete NO ACTION
ALTER TABLE Album DROP FOREIGN KEY FK_AlbumArtistId
drop table `Album`
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)