Sprievodca po zverejnenom rámci Kotlin

1. Úvod

V tomto výučbe sa pozrieme na to, ako dotazovať relačnú databázu pomocou príkazu Exposed.

Vystavená je knižnica otvoreného zdroja (licencia Apache) vyvinutá spoločnosťou JetBrains, ktorá poskytuje idiomatické Kotlin API pre niektoré implementácie relačných databáz a zmierňuje rozdiely medzi dodávateľmi databáz.

Exposed je možné použiť ako vysokoúrovňový DSL nad SQL, tak aj ako ľahký ORM (Object-Relational Mapping). V priebehu tohto tutoriálu teda pokryjeme obe použitia.

2. Odkryté nastavenie rámca

Exposed ešte nie je na Maven Central, takže musíme použiť vyhradené úložisko:

  vystavený vystavený //dl.bintray.com/kotlin/exposed 

Potom môžeme zahrnúť knižnicu:

 org.jetbrains.exponované vystavené 0,10,4 

V nasledujúcich častiach si tiež ukážeme príklady použitia databázy H2 v pamäti:

 com.h2database h2 1.4.197 

Nájdeme najnovšiu verziu programu Exposed on Bintray a najnovšiu verziu H2 na serveri Maven Central.

3. Pripojenie k databáze

Definujeme databázové spojenia s Databáza trieda:

Database.connect ("jdbc: h2: mem: test", driver = "org.h2.Driver")

Môžeme určiť aj a používateľ a a heslo ako pomenované parametre:

Database.connect ("jdbc: h2: mem: test", driver = "org.h2.Driver", user = "ja", heslo = "tajomstvo")

Všimnite si, že vyvolanie spojiť okamžite nenadväzuje spojenie s DB. Iba uloží parametre pripojenia na neskôr.

3.1. Ďalšie parametre

Ak potrebujeme uviesť ďalšie parametre pripojenia, použijeme iné preťaženie spojiť metóda, ktorá nám dáva úplnú kontrolu nad akvizíciou databázového pripojenia:

Database.connect ({DriverManager.getConnection ("jdbc: h2: mem: test; MODE = MySQL")})

Táto verzia spojiť vyžaduje parameter uzávierky. Exposed vyvolá uzávierku, kedykoľvek potrebuje nové pripojenie k databáze.

3.2. Pomocou a Dátový zdroj

Ak sa namiesto toho pripojíme k databáze pomocou a Dátový zdroj, ako to zvyčajne v podnikových aplikáciách býva (napr. aby sme mohli ťažiť zo spoločného zdieľania pripojení), môžeme použiť príslušné spojiť preťaženie:

Database.connect (zdroj údajov)

4. Otvorenie transakcie

Každá databázová operácia v Exposed vyžaduje aktívnu transakciu.

The transakcia metóda uzavrie a vyvolá ju pomocou aktívnej transakcie:

transakcia {// Do super vecí}

The transakcia vráti, čo vráti uzávierka. Potom Exposed automaticky ukončí transakciu po ukončení vykonávania bloku.

4.1. Commit and rollback

Keď transakcia blok sa úspešne vráti, Exposed sa zaviaže k transakcii. Keď namiesto toho dôjde k uzávierke vyvolaním výnimky, rámec vráti transakciu späť.

Transakciu môžeme tiež potvrdiť manuálne alebo vrátiť späť. Uzávierka, ktorú poskytujeme transakcia je v skutočnosti inštanciou Transakcia triedy vďaka Kotlinovej mágii.

Takto máme a spáchať a a rollback dostupná metóda:

transakcia {// Vykonať nejaké veci potvrdiť () // Vykonať ďalšie veci}

4.2. Výpisy z denníka

Pri učení sa rámca alebo ladení by sa nám mohlo hodiť skontrolovať príkazy a dotazy SQL, ktoré Exposed odosiela do databázy.

Takýto záznamník môžeme ľahko pridať k aktívnej transakcii:

transakcia {addLogger (StdOutSqlLogger) // robiť veci}

5. Definovanie tabuliek

V Exposed zvyčajne nepracujeme so surovými reťazcami a názvami SQL. Namiesto toho definujeme tabuľky, stĺpce, kľúče, vzťahy atď. Pomocou protokolu DSL na vysokej úrovni.

Každú tabuľku reprezentujeme inštanciou Tabuľka trieda:

objekt StarWarsFilms: Table ()

Exposed automaticky počíta názov tabuľky z názvu triedy, ale môžeme uviesť aj explicitný názov:

objekt StarWarsFilms: Tabuľka ("STAR_WARS_FILMS")

5.1. Stĺpce

Tabuľka nemá zmysel bez stĺpcov. Stĺpce definujeme ako vlastnosti našej tabuľkovej triedy:

objekt StarWarsFilms: Table () {val id = integer ("id"). autoIncrement (). primaryKey () val sequelId = integer ("sequel_id"). uniqueIndex () val name = varchar ("name", 50) riaditeľ val = varchar ("director", 50)}

Typy sme kvôli stručnosti vynechali, pretože Kotlin ich pre nás môže odvodiť. Každý stĺpec je každopádne typu Stĺpec a má názov, typ a prípadne parametre typu.

5.2. Primárne kľúče

Ako vidíme z príkladu v predchádzajúcej časti, môžeme ľahko definovať indexy a primárne kľúče pomocou plynulého API.

Pre bežný prípad tabuľky s celočíselným primárnym kľúčom však Exposed poskytuje triedy IntIdTable a LongIdTable ktoré pre nás definujú kľúč:

objekt StarWarsFilms: IntIdTable () {val sequelId = integer ("sequel_id"). uniqueIndex () val name = varchar ("name", 50) val director = varchar ("director", 50)}

K dispozícii je tiež UUIDTable; ďalej môžeme definovať svoje vlastné varianty podtriedou IdTable.

5.3. Zahraničné kľúče

Cudzie kľúče sa dajú ľahko predstaviť. Profitujeme tiež zo statického písania, pretože sa vždy odvolávame na vlastnosti známe v čase kompilácie.

Predpokladajme, že chceme sledovať mená hercov hrajúcich v jednotlivých filmoch:

objekt Hráči: Table () {val sequelId = integer ("sequel_id") .uniqueIndex () .references (StarWarsFilms.sequelId) val name = varchar ("name", 50)}

Aby ste sa vyhli pravopisu typu stĺpca (v tomto prípade celé číslo) keď to možno odvodiť z referenčného stĺpca, môžeme použiť odkaz metóda ako skratka:

val sequelId = referencia ("sequel_id", StarWarsFilms.sequelId) .uniqueIndex ()

Ak je odkaz na primárny kľúč, môžeme vynechať názov stĺpca:

val filmId = referencia ("film_id", StarWarsFilms)

5.4. Vytváranie tabuliek

Tabuľky môžeme vytvoriť tak, ako je definované vyššie programovo:

transakcia {SchemaUtils.create (StarWarsFilms, Hráči) // Robiť veci}

Tabuľky sa vytvárajú, iba ak ešte neexistujú. Neexistuje však žiadna podpora pre migráciu databáz.

6. Dotazy

Keď sme definovali niektoré tabuľkové triedy, ako sme si ukázali v predchádzajúcich častiach, môžeme vydávať dotazy do databázy pomocou rozširujúcich funkcií poskytovaných architektúrou.

6.1. Vybrať všetko

Na extrakciu dát z databázy používame Dopyt objekty zostavené z tabulkových tried. Najjednoduchší dotaz je ten, ktorý vráti všetky riadky danej tabuľky:

val dotaz = StarWarsFilms.selectAll ()

Dotaz je Iterable, tak to podporuje pre každý:

query.forEach {assertTrue {it [StarWarsFilms.sequelId]> = 7}}

Parameter uzávierky, ktorý sa implicitne volá to v príklade vyššie je inštanciou ResultRow trieda. Môžeme to vidieť ako mapu označenú stĺpcom.

6.2. Výber podskupiny stĺpcov

Môžeme tiež zvoliť podmnožinu stĺpcov tabuľky, t. J. Vykonať projekciu pomocou znaku plátok metóda:

StarWarsFilms.slice (StarWarsFilms.name, StarWarsFilms.director) .selectAll () .forEach {assertTrue {it [StarWarsFilms.name] .startsWith ("The")}}

Používame plátok aj na stĺpec použiť funkciu:

StarWarsFilms.slice (StarWarsFilms.name.countDistinct ())

Často pri použití agregačných funkcií ako napr počítať a priem., v dotaze budeme potrebovať klauzulu o skupine. O skupine si povieme v časti 6.5.

6.3. Filtrovanie podľa výrazov Where

Vystavený obsahuje vyhradenú DSL pre kde výrazy, ktoré sa používajú na filtrovanie dotazov a iných typov príkazov. Toto je mini jazyk založený na vlastnostiach stĺpcov, s ktorými sme sa stretli už skôr, a na rade booleovských operátorov.

Toto je výraz kde:

{(StarWarsFilms.director ako „J.J.%“) a (StarWarsFilms.sequelId eq 7)}

Jeho typ je zložitý; je to podtrieda SqlExpressionBuilder, ktorý definuje operátorov ako napr ako, ekv. a. Ako vidíme, ide o postupnosť porovnaní kombinovaných s a a alebo operátorov.

Takýto výraz môžeme odovzdať vyberte metóda, ktorá opäť vráti dopyt:

val select = StarWarsFilms.select {...} assertEquals (1, select.count ())

Vďaka odvodeniu typu nemusíme vysvetľovať zložitý typ výrazu where, keď je priamo odovzdaný znaku vyberte metóda ako vo vyššie uvedenom príklade.

Pretože kde výrazy sú objekty Kotlin, neexistujú žiadne špeciálne ustanovenia pre parametre dotazu. Jednoducho používame premenné:

val sequelNo = 7 StarWarsFilms.select {StarWarsFilms.sequelId> = pokračovanie}

6.4. Pokročilé filtrovanie

The Dopyt predmety vrátené používateľom vyberte a jeho varianty majú množstvo metód, ktoré môžeme použiť na spresnenie dotazu.

Možno budeme chcieť vylúčiť duplicitné riadky:

query.withDistinct (true) .forEach {...}

Alebo by sme mohli chcieť vrátiť iba podmnožinu riadkov, napríklad pri stránkovaní výsledkov pre používateľské rozhranie:

query.limit (20, offset = 40). forEach {...}

Tieto metódy vrátia nový Dopyt, aby sme ich mohli ľahko zreťaziť.

6.5. objednaťAutor: a SkupinaAutor:

The Query.orderBy metóda prijíma zoznam stĺpcov namapovaných na a SortOrder hodnota označujúca, či má byť zoradenie vzostupné alebo zostupné:

query.orderBy (StarWarsFilms.name do SortOrder.ASC)

Zatiaľ čo zoskupenie podľa jedného alebo viacerých stĺpcov, ktoré je užitočné najmä pri použití agregačných funkcií (pozri časť 6.2.), Sa dosahuje použitím skupinaBy metóda:

StarWarsFilms .slice (StarWarsFilms.sequelId.count (), StarWarsFilms.director) .selectAll () .groupBy (StarWarsFilms.director)

6.6. Pripája sa

Spojenia sú pravdepodobne jedným z predajných miest relačných databáz. V najjednoduchších prípadoch, keď máme cudzí kľúč a žiadne podmienky spojenia, môžeme použiť jedného z integrovaných operátorov spojenia:

(StarWarsFilms innerJoin Player) .selectAll ()

Tu sme ukázali internalJoin, ale na rovnakom princípe máme k dispozícii aj ľavé, pravé a krížové spojenie.

Potom môžeme pridať podmienky spojenia s výrazom where; napríklad ak nie je cudzí kľúč a musíme explicitne vykonať spojenie:

(StarWarsFilms innerJoin Hráči). Vyberte {StarWarsFilms.sequelId eq Players.sequelId}

Úplná forma spojenia je vo všeobecnosti nasledovná:

val complexJoin = Pripojiť sa (StarWarsFilms, Hráči, onColumn = StarWarsFilms.sequelId, otherColumn = Hráči.sequelId, joinType = JoinType.INNER, additionalConstraint = {StarWarsFilms.sequelId eq 8}) complexJoin.selectAll ()

6.7. Aliasing

Vďaka mapovaniu názvov stĺpcov na vlastnosti nepotrebujeme v bežnom spojení žiadne aliasingy, aj keď majú stĺpce rovnaký názov:

(StarWarsFilms innerJoin Players) .selectAll () .forEach {assertEquals (it [StarWarsFilms.sequelId], it [Players.sequelId])}

V skutočnosti vo vyššie uvedenom príklade StarWarsFilms.sequelId a Players.sequelId sú rôzne stĺpce.

Keď sa však rovnaká tabuľka v dotaze objaví viackrát, môžeme jej dať alias. Na to používame alias funkcia:

val sequel = StarWarsFilms.alias ("pokračovanie")

Potom môžeme alias použiť trochu ako tabuľku:

Pripojte sa (StarWarsFilms, sequel, additionalConstraint = {sequel [StarWarsFilms.sequelId] eq StarWarsFilms.sequelId + 1}). SelectAll (). ForEach {assertEquals (it [sequel [StarWarsFilms.sequelId]], it [StarWarsFilms.sequel )}

Na vyššie uvedenom príklade vidíme, že pokračovanie alias je tabuľka zúčastňujúca sa na spojení. Ak chceme získať prístup k niektorému z jeho stĺpcov, ako kľúč použijeme stĺpec aliasovanej tabuľky:

pokračovanie [StarWarsFilms.sequelId]

7. Vyhlásenia

Teraz, keď sme videli, ako dotazovať databázu, pozrime sa, ako vykonávať príkazy DML.

7.1. Vkladanie údajov

Pre vloženie údajov voláme jednu z variantov vložiť funkcie. Všetky varianty majú uzavretie:

StarWarsFilms.insert {it [name] = "The Last Jedi" it [sequelId] = 8 it [director] = "Rian Johnson"}

Do uzávierky vyššie sú zapojené dva pozoruhodné objekty:

  • toto (samotné uzavretie) je inštanciou StarWarsFilms trieda; to je dôvod, prečo môžeme získať prístup k stĺpcom, ktoré sú vlastnosťami, podľa ich nekvalifikovaného názvu
  • to (parameter uzávierky) je InsertStatement; it je štruktúra podobná mape so slotom pre každý stĺpec na vloženie

7.2. Extrakcia hodnôt stĺpca s automatickým prírastkom

Keď máme príkaz vloženia s automaticky generovanými stĺpcami (zvyčajne s automatickým prírastkom alebo sekvenciami), možno budeme chcieť získať vygenerované hodnoty.

V typickom prípade máme iba jednu vygenerovanú hodnotu a dorovnáme insertAndGetId:

val id = StarWarsFilms.insertAndGetId {it [name] = "The Last Jedi" it [sequelId] = 8 it [director] = "Rian Johnson"} assertEquals (1, id.value)

Ak máme viac ako jednu vygenerovanú hodnotu, môžeme ich prečítať podľa názvu:

val insert = StarWarsFilms.insert {it [name] = "Sila sa prebúdza" it [sequelId] = 7 it [director] = "J.J. Abrams"} assertEquals (2, vložte [StarWarsFilms.id] ?. hodnota)

7.3. Aktualizácia údajov

To, čo sme sa dozvedeli o dotazoch a vkladaní, teraz môžeme použiť na aktualizáciu existujúcich údajov v databáze. Jednoduchá aktualizácia skutočne vyzerá ako kombinácia výberu s prílohou:

StarWarsFilms.update ({StarWarsFilms.sequelId eq 8}) {it [name] = "Episode VIII - The Last Jedi"}

Vidíme použitie výrazu kde v kombinácii s UpdateStatement uzáver. V skutočnosti, UpdateStatement a InsertStatement zdieľať väčšinu API a logiky prostredníctvom spoločnej nadtriedy, UpdateBuilder, ktorá poskytuje možnosť nastaviť hodnotu stĺpca pomocou tvarových hranatých zátvoriek.

Ak potrebujeme aktualizovať stĺpec výpočtom novej hodnoty zo starej hodnoty, využijeme SqlExpressionBuilder:

StarWarsFilms.update ({StarWarsFilms.sequelId eq 8}) {with (SqlExpressionBuilder) {it.update (StarWarsFilms.sequelId, StarWarsFilms.sequelId + 1)}}

Toto je objekt, ktorý poskytuje operátory infix (ako plus, mínus a tak ďalej), ktoré môžeme použiť na zostavenie inštrukcie na aktualizáciu.

7.4. Mazanie údajov

Nakoniec môžeme údaje vymazať pomocou deleteWhere metóda:

StarWarsFilms.deleteWhere ({StarWarsFilms.sequelId eq 8})

8. DAO API, ľahký ORM

Doteraz sme používali Exposed na priame mapovanie z operácií na objektoch Kotlin na dotazy a príkazy SQL. Každá metóda sa volá vložiť, aktualizovať, vybrať atď. vedie k okamžitému odoslaniu reťazca SQL do databázy.

Exposed má však tiež DAO API na vyššej úrovni, ktoré predstavuje jednoduchý ORM. Poďme sa do toho teraz ponoriť.

8.1. Subjekty

V predchádzajúcich častiach sme triedy používali na reprezentáciu databázových tabuliek a na vyjadrenie operácií nad nimi pomocou statických metód.

Ak sa posunieme o krok ďalej, môžeme definovať entity založené na tých tabuľkových triedach, kde každá inštancia entity predstavuje riadok databázy:

trieda StarWarsFilm (id: EntityID): Entita (id) {sprievodný objekt: EntityClass (StarWarsFilms) var sequelId od StarWarsFilms.sequelId var meno od StarWarsFilms.name var director od StarWarsFilms.director}

Poďme si teraz po častiach analyzovať vyššie uvedenú definíciu.

V prvom riadku vidíme, že entita je trieda rozširujúca sa Subjekt. Má ID so špecifickým typom, v tomto prípade Int.

trieda StarWarsFilm (id: EntityID): Entita (id) {

Potom sa stretneme s definíciou sprievodného objektu. Sprievodný objekt predstavuje triedu entity, to znamená statické metadáta definujúce entitu a operácie, ktoré s ňou môžeme vykonávať.

Ďalej vo vyhlásení sprievodného objektu spájame entitu, StarWarsFilm - jednotného čísla, pretože predstavuje jeden riadok k stolu, StarWarsFilms - množné číslo, pretože predstavuje kolekciu všetkých riadkov.

sprievodný objekt: EntityClass (StarWarsFilms)

Nakoniec máme vlastnosti implementované ako delegáti vlastností do zodpovedajúcich stĺpcov tabuľky.

var sequelId od StarWarsFilms.sequelId var názov podľa StarWarsFilms.name var director od StarWarsFilms.director

Všimnite si, že predtým sme stĺpce deklarovali pomocou val pretože sú to nemenné metadáta. Teraz namiesto toho deklarujeme vlastnosti entity pomocou var, pretože sú premenlivými slotmi v riadku databázy.

8.2. Vkladanie údajov

Ak chcete vložiť riadok do tabuľky, jednoducho vytvoríme novú inštanciu našej triedy entít pomocou metódy statickej továrne Nový v transakcii:

val theLastJedi = StarWarsFilm.new {name = "The Last Jedi" sequelId = 8 director = "Rian Johnson"}

Upozorňujeme, že operácie proti databáze sa vykonávajú lenivo; vydávajú sa, až keď teplá keška je začervenaný. Pre porovnanie, režim dlhodobého spánku nazýva Hibernate a zasadanie.

To sa deje automaticky, keď je to potrebné; napr. po prvom prečítaní vygenerovaného identifikátora Exposed potichu vykoná príkaz insert:

assertEquals (1, theLastJedi.id.value) // Čítanie ID spôsobí začervenanie

Porovnajte toto správanie s vložiť metóda z časti 7.1., ktorá okamžite vydá vyhlásenie k databáze. Tu pracujeme na vyššej úrovni abstrakcie.

8.3. Aktualizácia a mazanie objektov

Na aktualizáciu riadku jednoducho priradíme jeho vlastnosti:

theLastJedi.name = "Epizóda VIII - Posledný Jedi"

Zatiaľ čo chceme vymazať objekt, ktorý voláme vymazať na to:

theLastJedi.delete ()

Ako s Nový, aktualizácia a operácie sa vykonávajú lenivo.

Aktualizácie a vymazania je možné vykonať iba na predtým načítanom objekte. Neexistuje API pre rozsiahle aktualizácie a mazania. Namiesto toho musíme použiť API na nižšej úrovni, ktoré sme videli v sekcii 7. Tieto dve API je možné použiť súčasne v jednej transakcii.

8.4. Dopyt

Pomocou rozhrania DAO API môžeme vykonávať tri typy dotazov.

Na načítanie všetkých objektov bez podmienok používame statickú metódu všetky:

val filmy = StarWarsFilm.all ()

Na načítanie jedného objektu podľa ID voláme findById:

val theLastJedi = StarWarsFilm.findById (1)

Ak s týmto ID nie je žiadny objekt, findById vracia nulový.

Nakoniec použijeme všeobecný prípad Nájsť s výrazom kde:

val movies = StarWarsFilm.find {StarWarsFilms.sequelId eq 8}

8.5. Združenia typu „všetko v jednom“

Rovnako ako spojenia sú dôležitou vlastnosťou relačných databáz, mapovanie spojení na referencie je dôležitým aspektom ORM. Pozrime sa teda, čo ponúka Exposed.

Predpokladajme, že chceme sledovať hodnotenie každého filmu používateľmi. Najskôr definujeme dve ďalšie tabuľky:

object Users: IntIdTable () {val name = varchar ("name", 50)} object UserRatings: IntIdTable () {val value = long ("value") val film = reference ("film", StarWarsFilms) val user = reference („používateľ“, používatelia)}

Potom napíšeme zodpovedajúce entity. Vynechajme Používateľ entita, ktorá je triviálna, a prejsť priamo k Užívateľské hodnotenie trieda:

trieda UserRating (id: EntityID): IntEntity (id) {sprievodný objekt: IntEntityClass (UserRatings) var hodnota podľa UserRatings.value var film od StarWarsFilm referencedOn UserRatings.film var užívateľ podľa User referencedOn UserRatings.user}

Všimnite si najmä: referencedOn metóda infix vyvoláva vlastnosti, ktoré reprezentujú asociácie. Vzor je nasledovný: a var vyhlásenie, od odkazovaný subjekt, referencedOn referenčný stĺpec.

Vlastnosti deklarované týmto spôsobom sa správajú ako bežné vlastnosti, ale ich hodnota je priradený objekt:

val someUser = User.new {name = "Some User"} val hodnotenie = UserRating.new {hodnota = 9 user = someUser film = theLastJedi} assertEquals (theLastJedi, rating.film)

8.6. Nepovinné združenia

Asociácie, ktoré sme videli v predchádzajúcej časti, sú povinné, to znamená, že musíme vždy uvádzať hodnotu.

Ak chceme voliteľné združenie, musíme najskôr v tabuľke stĺpec vyhlásiť za neplatný:

val user = reference ("user", Users) .nullable ()

Potom použijeme optionalReferencedOn namiesto referencedOn v subjekte:

var user by User optionalReferencedOn UserRatings.user

Týmto spôsobom používateľ majetok bude mať povolenú hodnotu.

8.7. Združenia one-to-many

Možno by sme chceli zmapovať aj opačnú stranu asociácie. Hodnotenie sa týka filmu, to je to, čo modelujeme v databáze pomocou cudzieho kľúča; film má preto niekoľko hodnotení.

Na mapovanie hodnotení filmu jednoducho pridáme nehnuteľnosť na „jednu“ stranu asociácie, teda filmovú entitu v našom príklade:

trieda StarWarsFilm (id: EntityID): Entita (id) {// Ostatné vlastnosti zmenili hodnotenie podľa UserRating referrersOn UserRatings.film}

Vzorec je podobný ako vo vzťahu medzi dvoma, ale využíva sa referrersOn. Takto definovaná vlastnosť je Iterable, aby sme to mohli prekonať s pre každý:

theLastJedi.ratings.forEach {...}

Upozorňujeme, že na rozdiel od bežných vlastností sme ich definovali hodnotení s val. Vlastnosť je skutočne nemenná, môžeme ju iba čítať.

Hodnota vlastnosti nemá tiež API pre mutáciu. Aby sme teda mohli pridať nové hodnotenie, musíme ho vytvoriť s odkazom na film:

UserRating.new {value = 8 user = someUser film = theLastJedi}

Potom film hodnotení zoznam bude obsahovať novo pridané hodnotenie.

8.8. Združenia typu mnoho proti mnohým

V niektorých prípadoch možno budeme potrebovať združenie mnohých od mnohých. Povedzme, že chceme pridať referenciu an Herci stôl k StarWarsFilm trieda:

object Actors: IntIdTable () {val firstname = varchar ("firstname", 50) val lastname = varchar ("lastname", 50)} class Actor (id: EntityID): IntEntity (id) {companion object: IntEntityClass (Actors) var meno podľa Actors.firstname var priezvisko podľa Actors.lastname}

Po definovaní tabuľky a entity potrebujeme ďalšiu tabuľku, ktorá bude zastupovať asociáciu:

objekt StarWarsFilmActors: Table () {val starWarsFilm = referencia ("starWarsFilm", StarWarsFilms) .primaryKey (0) val herec = referencia ("herec", herci) .primaryKey (1)}

Tabuľka má dva stĺpce, ktoré sú cudzími kľúčmi a ktoré tiež tvoria zložený primárny kľúč.

Na záver môžeme spojiť asociačnú tabuľku s StarWarsFilm subjekt:

trieda StarWarsFilm (id: EntityID): IntEntity (id) {sprievodný objekt: IntEntityClass (StarWarsFilms) // Ostatné vlastnosti priniesli var hercov podľa herca prostredníctvom StarWarsFilmActors}

V čase písania tohto článku nie je možné vytvoriť entitu s vygenerovaným identifikátorom a zahrnúť ju do asociácie viacerých proti jednej transakcii.

V skutočnosti musíme použiť viac transakcií:

// Najskôr vytvorte film val film = transakcia {StarWarsFilm.new {name = "Posledný Jedi" sequelId = 8 director = "Rian Johnson" r}} // Potom vytvorte herca val herec = transakcia {Actor.new {firstname = "Daisy" lastname = "Ridley"}} // Nakoniec prepojte tieto dve transakcie {film.actors = SizedCollection (listOf (actor))}

Tu sme pre pohodlie použili tri rôzne transakcie. Dve by však boli dostatočné.

9. Záver

V tomto článku sme poskytli podrobný prehľad rámca Exposed pre Kotlin. Ďalšie informácie a príklady nájdete na stránke Exposed wiki.

Implementáciu všetkých týchto príkladov a útržkov kódu nájdete v projekte GitHub.


$config[zx-auto] not found$config[zx-overlay] not found