Útmutató a Kotlin Exposed Framework-hez

1. Bemutatkozás

Ebben az oktatóanyagban megvizsgáljuk, hogyan lehet lekérdezni egy relációs adatbázist az Exposed segítségével.

Az Exposed a JetBrains által kifejlesztett nyílt forráskódú könyvtár (Apache licenc), amely egy idiomatikus Kotlin API-t biztosít néhány relációs adatbázis-megvalósításhoz, miközben elsimítja az adatbázis-gyártók közötti különbségeket.

Az Exposed egyaránt használható magas szintű DSL-ként SQL felett és könnyű ORM-ként (Object-Relational Mapping). Így a bemutató során mindkét felhasználásra kiterjedünk.

2. Kitett keretrendszer beállítása

Az Exposed még nincs a Maven Centralon, ezért külön tárhelyet kell használnunk:

  ki van téve //dl.bintray.com/kotlin/exposed 

Ezután felvehetjük a könyvtárat:

 org.jetbrains.exposed expozícióval 0.10.4 

A következő szakaszokban példákat mutatunk be a memóriában található H2 adatbázis használatával:

 com.h2adatbázis h2 1.4.197 

Megtalálhatjuk az Exposed on Bintray legújabb verzióját és a H2 legújabb verzióját a Maven Central-on.

3. Csatlakozás az adatbázishoz

Meghatározzuk az adatbázis-kapcsolatokat a Adatbázis osztály:

Database.connect ("jdbc: h2: mem: test", illesztőprogram = "org.h2.Driver")

Megadhatjuk a felhasználó és a Jelszó megnevezett paraméterekként:

Database.connect ("jdbc: h2: mem: test", driver = "org.h2.Driver", user = "jómagam", password = "titkos")

Ne feledje, hogy meghívva csatlakozzon nem hoz létre azonnal kapcsolatot a DB-vel. Csak a kapcsolati paramétereket menti későbbre.

3.1. További paraméterek

Ha más kapcsolati paramétereket kell megadnunk, akkor a rendszer másik túlterhelését fogjuk használni csatlakozzon módszer, amely teljes ellenőrzést biztosít számunkra az adatbázis-kapcsolat megszerzése felett:

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

Ez a verzió csatlakozzon zárási paramétert igényel. Az Exposed a bezárást hívja elő, amikor új kapcsolatra van szüksége az adatbázissal.

3.2. Használva Adatforrás

Ha ehelyett az a használatával csatlakozunk az adatbázishoz Adatforrás, mint általában a vállalati alkalmazásoknál (például a kapcsolat-pooling előnyeinek kihasználása érdekében), használhatjuk a megfelelőt csatlakozzon túlterhelés:

Database.connect (adatforrás)

4. Tranzakció megnyitása

Az Exposed minden adatbázis-műveletéhez aktív tranzakcióra van szükség.

A tranzakció metódus lezárást igényel és aktív tranzakcióval hívja meg:

tranzakció {// Do cool stuff}

A tranzakció bármit is ad vissza a zár. Ezután az Exposed automatikusan lezárja a tranzakciót, amikor a blokk végrehajtása befejeződik.

4.1. Vállalás és visszagörgetés

Amikor az tranzakció blokk sikeresen visszatér, az Exposed végrehajtja a tranzakciót. Amikor ehelyett a lezárás kivételt dob, a keretrendszer visszagörgeti a tranzakciót.

Manuálisan is elvégezhetünk vagy visszavonhatunk tranzakciót. A bezárás, amelyet biztosítunk tranzakció valójában a Tranzakció osztály a Kotlin varázslatnak köszönhetően.

Így van egy elkövetni és a visszagörgetés rendelkezésre álló módszer:

tranzakció {// Csináljon valamilyen dolgot ((//) Csináljon más dolgokat}

4.2. Nyilatkozatok naplózása

A keretrendszer elsajátításakor vagy a hibakeresés során hasznosnak tarthatjuk megvizsgálni az SQL utasításokat és lekérdezéseket, amelyeket az Exposed küld az adatbázisnak.

Könnyen hozzáadhatunk egy ilyen naplózót az aktív tranzakcióhoz:

tranzakció {addLogger (StdOutSqlLogger) // Do stuff}

5. Táblázatok meghatározása

Általában az Exposed részben nem dolgozunk nyers SQL karakterláncokkal és nevekkel. Ehelyett táblákat, oszlopokat, kulcsokat, kapcsolatokat stb. Határozunk meg, magas szintű DSL használatával.

Minden táblázatot a asztal osztály:

StarWarsFilms objektum: Táblázat ()

Az Exposed automatikusan kiszámítja a táblázat nevét az osztály nevéből, de megadhatunk egy explicit nevet is:

StarWarsFilms: Table ("STAR_WARS_FILMS") objektum

5.1. Oszlopok

A táblázat oszlopok nélkül értelmetlen. Az oszlopokat a táblaosztályunk tulajdonságaként definiáljuk:

objektum StarWarsFilms: Táblázat () {val id = egész szám ("id"). autoIncrement (). primaryKey () val sequelId = egész szám ("sequel_id"). egyediIndex () val név = varchar ("név", 50) val igazgató = varchar ("igazgató", 50)}

A rövidség érdekében kihagytuk a típusokat, mivel Kotlin következtethet rájuk. Egyébként minden oszlop típusa van Oszlop és van neve, típusa és esetleg típusparaméterei.

5.2. Elsődleges kulcsok

Amint az előző szakasz példájából láthatjuk, könnyen meghatározhatjuk az indexeket és az elsődleges kulcsokat egy folyékony API-val.

Azonban egy egész számú elsődleges kulccsal rendelkező tábla általános esetére az Exposed osztályokat ad IntIdTable és LongIdTable amelyek meghatározzák számunkra a kulcsot:

objektum StarWarsFilms: IntIdTable () {val sequelId = egész szám ("sequel_id"). uniqueIndex () val név = varchar ("név", 50) val director = varchar ("igazgató", 50)}

Van még egy UUIDTable; ezenkívül alosztályozással meghatározhatjuk saját változatainkat IdTable.

5.3. Külföldi kulcsok

Az idegen kulcsokat könnyű bevezetni. A statikus tipizálásból azért is profitálunk, mert mindig a fordításkor ismert tulajdonságokra hivatkozunk.

Tegyük fel, hogy szeretnénk nyomon követni az egyes filmekben játszó színészek nevét:

object Players: Táblázat () {val sequelId = egész szám ("sequel_id") .uniqueIndex () .references (StarWarsFilms.sequelId) val name = varchar ("név", 50)}

Az oszlop típusának megírásának elkerülése érdekében (ebben az esetben egész szám), amikor a hivatkozott oszlopból levezethető, használhatjuk a referencia módszer gyorsírásként:

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

Ha a hivatkozás az elsődleges kulcsra vonatkozik, akkor elhagyhatjuk az oszlop nevét:

val filmId = referencia ("film_id", StarWarsFilms)

5.4. Táblázatok készítése

Programszerűen létrehozhatjuk a táblázatokat a fentiek szerint:

tranzakció {SchemaUtils.create (StarWarsFilms, Players) // Do stuff}

A táblák csak akkor jönnek létre, ha még nem léteznek. Az adatbázis-migrációk azonban nem támogatottak.

6. Lekérdezések

Miután meghatároztunk néhány táblázati osztályt, amint azt az előző szakaszokban bemutattuk, a keretrendszer által biztosított bővítményfüggvények segítségével lekérdezéseket adhatunk ki az adatbázis számára.

6.1. Mindet kiválaszt

Adatok kinyeréséhez az adatbázisból használjuk Lekérdezés táblaosztályokból felépített objektumok. A legegyszerűbb az a lekérdezés, amely az adott táblázat összes sorát visszaadja:

val query = StarWarsFilms.selectAll ()

A lekérdezés egy Iterable, tehát támogatja az egyes:

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

A zárási paraméter, amelyet implicit módon hívnak azt a fenti példában a ResultRow osztály. Oszloponként kulcsolt térképként láthatjuk.

6.2. Oszlopok részhalmazának kiválasztása

Kiválaszthatjuk a tábla oszlopainak egy részhalmazát is, azaz kivetítést hajthatunk végre a szelet módszer:

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

Használunk szelet függvény oszlopra történő alkalmazásához is:

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

Gyakran olyan összesített függvények használatakor, mint pl számol és átlag, szükségünk lesz egy csoportra tagmondattal a lekérdezésben. A csoportról a 6.5 szakaszban fogunk beszélni.

6.3. Szűrés a kifejezések helyével

Az Exposed egy dedikált DSL-t tartalmaz a hol kifejezések, amelyeket a lekérdezések és más típusú utasítások szűrésére használnak. Ez egy mini nyelv a korábban tapasztalt oszloptulajdonságok és a logikai operátorok sora alapján.

Ez egy olyan kifejezés, ahol:

{(StarWarsFilms.director, mint a "J.J.%") és (StarWarsFilms.sequelId eq 7)}

Típusa összetett; alosztálya SqlExpressionBuilder, amely meghatározza az olyan operátorokat, mint a mint, egyenlő és. Mint láthatjuk, ez az összehasonlítások sorozata együtt van kombinálva és és vagy üzemeltetők.

Ilyen kifejezést átadhatunk a válassza metódus, amely ismét lekérdezést ad vissza:

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

A típus következtetésnek köszönhetően nem kell megfogalmaznunk a hol kifejezés komplex típusát, amikor azt közvetlenül átadják a válassza módszer, mint a fenti példában.

Mivel a kifejezések Kotlin objektumok, a lekérdezési paraméterekre vonatkozóan nincsenek külön rendelkezések. Egyszerűen használunk változókat:

val sequelNo = 7 StarWarsFilms.select {StarWarsFilms.sequelId> = sequelNo}

6.4. Speciális szűrés

A Lekérdezés által visszaadott tárgyak válassza és változatai számos módszerrel rendelkeznek, amelyekkel finomíthatjuk a lekérdezést.

Például kizárhatjuk az ismétlődő sorokat:

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

Vagy lehet, hogy csak a sorok egy részhalmazát szeretnénk visszaadni, például az UI eredményeinek lapozásakor:

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

Ezek a módszerek újat adnak vissza Lekérdezés, így könnyen láncolhatjuk őket.

6.5. RendelésÁltal és CsoportÁltal

A Query.orderBy metódus elfogadja az a-hoz rendelt oszlopok listáját Sorrend érték, amely jelzi, hogy a rendezésnek növekvő vagy csökkenő legyen-e:

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

Míg az egy vagy több oszlop szerinti csoportosítás, különösen az összesített függvények használata esetén (lásd a 6.2. Szakaszt), a csoportosít módszer:

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

6.6. Csatlakozik

A csatlakozások vitathatatlanul a relációs adatbázisok egyik eladási pontja. A legegyszerűbb esetekben, amikor van egy külföldi kulcsunk és nincsenek csatlakozási feltételek, használhatjuk a beépített csatlakozási operátorok egyikét:

(StarWarsFilms innerJoin Players) .selectAll ()

Itt megmutattuk belső összekapcsolás, de ugyanezzel az elvvel rendelkezünk bal-, jobb- és keresztcsatlakozással is.

Ezután hozzáadhatunk csatlakozási feltételeket egy hol kifejezéssel; például, ha nincs idegen kulcs, és kifejezetten el kell végeznünk a csatlakozást:

(StarWarsFilms innerJoin Players). Válassza a {StarWarsFilms.sequelId eq Players.sequelId} lehetőséget

Általános esetben a csatlakozás teljes formája a következő:

val complexJoin = Csatlakozás (StarWarsFilms, Players, onColumn = StarWarsFilms.sequelId, otherColumn = Players.sequelId, joinType = JoinType.INNER, additionalConstraint = {StarWarsFilms.sequelId eq 8}) complexJoin.selectAll ()

6.7. Aliasing

Az oszlopnevek tulajdonságokhoz való hozzárendelésének köszönhetően egy tipikus összekapcsoláskor nincs szükségünk álnevekre, még akkor sem, ha az oszlopoknak véletlenül ugyanaz a neve:

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

Valójában a fenti példában StarWarsFilms.sequelId és Players.sequelId különböző oszlopok.

Ha azonban ugyanaz a táblázat többször is megjelenik egy lekérdezésben, akkor érdemes álnevet adni neki. Ehhez használjuk a álnév funkció:

val folytatás = StarWarsFilms.alias ("folytatás")

Ezután kissé használhatjuk az álnevet, mint egy táblázatot:

Csatlakozzon (StarWarsFilms, folytatás, továbbiConstraint = {folytatás [StarWarsFilms.sequelId] eq StarWarsFilms.sequelId + 1}). SelectAll (). ForEach {assertEquals (it [folytatás [StarWarsFilms.sequelId]], azt [StarWarsFilms.sequ )}

A fenti példában láthatjuk, hogy a folytatás alias egy asztal, amely részt vesz a csatlakozásban. Amikor hozzá akarunk férni az egyik oszlopához, az aliased tábla oszlopát használjuk kulcsként:

folytatás [StarWarsFilms.sequelId]

7. Nyilatkozatok

Most, hogy láttuk, hogyan kell lekérdezni az adatbázist, nézzük meg, hogyan kell végrehajtani a DML utasításokat.

7.1. Adatok beszúrása

Adatok beszúrásához meghívjuk a betét funkció. Minden változat bezárul:

StarWarsFilms.insert {it [name] = "Az utolsó Jedik" it [sequelId] = 8 it [rendező] = "Rian Johnson"}

Két figyelemre méltó tárgy vesz részt a fenti lezárásban:

  • ez (maga a bezárás) a StarWarsFilms osztály; ezért hozzáférhetünk az oszlopokhoz, amelyek tulajdonságok, minősítés nélküli nevükön
  • azt (a zárási paraméter) egy InsertStatement; ént egy térképszerű szerkezet, ahol minden oszlop beillesztendő

7.2. Az automatikus növekményes oszlopértékek kinyerése

Ha rendelkezünk beszúró utasítással, automatikusan generált oszlopokkal (általában automatikus növekmény vagy szekvenciák), érdemes megszereznünk a létrehozott értékeket.

Tipikus esetben csak egy generált értékünk van, és hívunk insertAndGetId:

val id = StarWarsFilms.insertAndGetId {it [name] = "Az utolsó Jedik" it [sequelId] = 8 it [director] = "Rian Johnson"} assertEquals (1, id.value)

Ha több generált értékünk van, név szerint olvashatjuk őket:

val insert = StarWarsFilms.insert {it [name] = "Az erő felébreszti" it [sequelId] = 7 it [director] = "J.J. Abrams"} assertEquals (2, illessze be a [StarWarsFilms.id]? értéket)

7.3. Adatok frissítése

Most már felhasználhatjuk a lekérdezésekről és a beszúrásokról tanultakat az adatbázis meglévő adatainak frissítésére. Valójában az egyszerű frissítés úgy néz ki, mint egy select és egy insert kombinációja:

StarWarsFilms.update ({StarWarsFilms.sequelId eq 8}) {it [név] = "VIII. Rész - Az utolsó jedik"}

Láthatjuk, hogy egy ahol kifejezést egy-vel kombinálunk UpdateStatement bezárás. Valójában, UpdateStatement és InsertStatement megosztja az API és a logika nagy részét egy közös szuperosztályon keresztül, UpdateBuilder, amely lehetőséget nyújt az oszlop értékének idiomatikus szögletes zárójelek segítségével történő beállítására.

Amikor egy oszlopot frissítenünk kell a régi érték új értékének kiszámításával, akkor kihasználjuk a SqlExpressionBuilder:

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

Ez egy olyan objektum, amely infix operátorokat (pl plusz, mínusz és így tovább), amelyekkel frissítési utasításokat készíthetünk.

7.4. Adatok törlése

Végül törölhetjük az adatokat a deleteWhere módszer:

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

8. A DAO API, egy könnyű ORM

Eddig az Exposed segítségével közvetlenül leképeztük a Kotlin-objektumok műveleteit az SQL-lekérdezésekre és utasításokra. Minden módszer meghívása tetszik beszúr, frissít, kiválaszt és így tovább egy SQL karakterláncot azonnal elküldenek az adatbázisba.

Az Exposed rendelkezik azonban egy magasabb szintű DAO API-val is, amely egy egyszerű ORM-et alkot. Merüljünk bele ebbe.

8.1. Entitások

Az előző szakaszokban osztályokat használtunk adatbázis táblák ábrázolására és a rajtuk végzett műveletek statikus módszerekkel történő kifejezésére.

Egy lépéssel tovább haladva meghatározhatunk entitásokat azon táblák osztályai alapján, ahol az entitás minden példánya egy adatbázis sort képvisel:

osztály StarWarsFilm (id: EntityID): Entitás (id) {társobjektum: EntityClass (StarWarsFilms) var folytatásazonosító: StarWarsFilms.sequelId var neve: StarWarsFilms.name var rendező: StarWarsFilms.director}

Most elemezzük darabonként a fenti meghatározást.

Az első sorban láthatjuk, hogy az entitás egy osztály, amely kiterjed Entitás. Van egy meghatározott típusú azonosítója, ebben az esetben Int.

osztály StarWarsFilm (id: EntityID): Entity (id) {

Ezután egy társobjektum-definícióval találkozunk. A társobjektum az entitásosztályt, vagyis az entitást meghatározó statikus metaadatokat és az általa elvégezhető műveleteket ábrázolja.

Továbbá a társobjektum deklarációjában összekapcsoljuk az entitást, StarWarsFilm - egyes szám, mivel egyetlen sort képvisel az asztalhoz, StarWarsFilms - többes szám, mert az összes sor gyűjteményét képviseli.

társobjektum: EntityClass (StarWarsFilms)

Végül megkapjuk azokat a tulajdonságokat, amelyeket tulajdonságmeghatalmazóként hajtunk végre a megfelelő táblázat oszlopokban.

var sequelId by StarWarsFilms.sequelId var name by StarWarsFilms.name var director by StarWarsFilms.director

Ne feledje, hogy korábban az oszlopokat a val mert megváltoztathatatlan metaadatok. Most ehelyett az entitás tulajdonságait deklaráljuk a var, mert ezek egy adatbázis sorban változtatható helyek.

8.2. Adatok beszúrása

Ha egy sort be akar illeszteni egy táblázatba, egyszerűen létre kell hoznia az entitásosztályunk új példányát a statikus gyári módszerrel új tranzakcióban:

val theLastJedi = StarWarsFilm.new {name = "Az utolsó Jedik" folytatásId = 8 rendező = "Rian Johnson"}

Vegye figyelembe, hogy az adatbázis elleni műveleteket lustán hajtják végre; csak akkor adják ki, ha a meleg gyorsítótár kipirul. Összehasonlításképpen, a Hibernate a meleg gyorsítótárat a ülés.

Ez szükség esetén automatikusan megtörténik; pl. az első alkalommal, amikor elolvassuk a generált azonosítót, az Exposed csendben végrehajtja az insert utasítást:

assertEquals (1, theLastJedi.id.value) // Az azonosító elolvasása öblítést okoz

Hasonlítsa össze ezt a viselkedést a betét módszer a 7.1. szakaszból, amely azonnal kiad egy nyilatkozatot az adatbázis ellen. Itt az absztrakció magasabb szintjén dolgozunk.

8.3. Objektumok frissítése és törlése

Egy sor frissítéséhez egyszerűen hozzárendeljük a tulajdonságait:

theLastJedi.name = "VIII. rész - Az utolsó jedik"

Miközben törölni akarunk egy objektumot, amelyet hívunk töröl Rajta:

theLastJedi.delete ()

Mint új, a frissítést és a műveleteket lustán végzik.

Frissítés és törlés csak egy korábban betöltött objektumon hajtható végre. A tömeges frissítésekhez és törlésekhez nincs API. Ehelyett azt az alacsonyabb szintű API-t kell használnunk, amelyet a 7. szakaszban láthattunk. Ennek ellenére a két API együtt használható ugyanabban a tranzakcióban.

8.4. Lekérdezés

A DAO API segítségével háromféle lekérdezést hajthatunk végre.

Az összes objektum feltétel nélküli betöltéséhez a statikus módszert alkalmazzuk minden:

val filmek = StarWarsFilm.all ()

Ha egyetlen objektumot szeretnénk betölteni azonosítónként, meghívjuk findById:

val theLastJedi = StarWarsFilm.findById (1)

Ha nincs objektum ezzel az azonosítóval, findById visszatér nulla.

Végül általános esetben használjuk megtalálja ahol kifejezés:

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

8.5. Sok-egy-egylet

Ahogy a kapcsolatok a relációs adatbázisok fontos jellemzője, a hivatkozásokhoz való kapcsolódások feltérképezése az ORM fontos szempontja. Lássuk, mit kínál az Exposed.

Tegyük fel, hogy nyomon akarjuk követni az egyes filmek felhasználói értékelését. Először két további táblázatot határozunk meg:

objektum Felhasználók: IntIdTable () {val name = varchar ("név", 50)} object UserRatings: IntIdTable () {val value = long ("value") val film = referencia ("film", StarWarsFilms) val user = referencia ("felhasználó", felhasználók)}

Ezután megírjuk a megfelelő entitásokat. Hagyjuk el a Felhasználó entitás, ami triviális, és egyenesen a Felhasználói értékelés osztály:

class UserRating (id: EntityID): IntEntity (id) {kísérőobjektum: IntEntityClass (UserRatings) var értéke UserRatings.value var film által StarWarsFilm referentedOn UserRatings.film var felhasználó által User hivatkozott UserRatings.user}

Különösen vegye figyelembe a referatedOn az infix metódus az asszociációkat képviselő tulajdonságokat hívja meg. A minta a következő: a var nyilatkozat, által a hivatkozott entitás, referatedOn a hivatkozási oszlop.

Az így deklarált tulajdonságok úgy viselkednek, mint a szokásos tulajdonságok, de értékük a társított objektum:

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

8.6. Választható egyesületek

Az előző szakaszban látott asszociációk kötelezőek, vagyis mindig meg kell adnunk egy értéket.

Ha opcionális társítást akarunk, akkor először az oszlopot érvénytelennek kell nyilvánítanunk a táblázatban:

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

Akkor használjuk választhatóReferencedOn ahelyett referatedOn az entitásban:

var felhasználó által User optionalReferencedOn UserRatings.user

Így a felhasználó tulajdonság érvénytelen lesz.

8.7. Egy a sokhoz egyesület

Érdemes feltérképezni az egyesület másik oldalát is. A minősítés egy filmről szól, ezt modellezzük az adatbázisban egy idegen kulccsal; következésképpen egy filmnek számos értékelése van.

A film értékeléseinek feltérképezéséhez egyszerűen hozzáadunk egy tulajdonságot az egyesület „egy” oldalához, vagyis a példánkban szereplő film entitáshoz:

osztály StarWarsFilm (id: EntityID): Entitás (id) {// Egyéb tulajdonságok, amelyeket a UserRating referrersOn UserRatings.film} értékelések elértek

A minta hasonló a sok az egyhez viszonyokhoz, de használja referrersOn. Az így definiált tulajdonság egy Iterable, így bejárhatjuk vele az egyes:

theLastJedi.ratings.forMinden {...}

Vegye figyelembe, hogy a szokásos tulajdonságokkal ellentétben mi definiáltuk értékelések val vel val. Valóban, a tulajdonság megváltoztathatatlan, csak olvashatjuk.

A tulajdonság értéke nem rendelkezik API-val a mutációhoz sem. Tehát egy új értékelés hozzáadásához létre kell hoznunk a filmre való hivatkozással:

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

Aztán a film értékelések lista tartalmazza az újonnan hozzáadott minősítést.

8.8. Sok-sok-sok egyesület

Bizonyos esetekben szükség lehet sok-sok társulásra. Tegyük fel, hogy hozzá akarunk adni egy referenciát és egy Színészek táblázat a StarWarsFilm osztály:

object Actors: IntIdTable () {val keresztnév = varchar ("keresztnév", 50) val vezetéknév = varchar ("vezetéknév", 50)} osztály Actor (id: EntityID): IntEntity (id) {társobjektum: IntEntityClass (szereplők) var keresztnév: Actors.firstname var vezetéknév: Actors.lastname}

Miután meghatározta a táblázatot és az entitást, szükségünk van egy másik táblára az asszociáció képviseletére:

objektum StarWarsFilmActors: Táblázat () {val starWarsFilm = referencia ("starWarsFilm", StarWarsFilms) .primaryKey (0) val színész = referencia ("színész", Színészek) .primaryKey (1)}

A táblázatnak két oszlopa van, amelyek mind idegen kulcsok, és amelyek összetett elsődleges kulcsot is alkotnak.

Végül összekapcsolhatjuk az asszociációs táblázatot a StarWarsFilm entitás:

osztály StarWarsFilm (id: EntityID): IntEntity (id) {társobjektum: IntEntityClass (StarWarsFilms) // Egyéb tulajdonságok a színészeket a színész elől a StarWarsFilmActors segítségével}

Az írás idején nem lehet létrehozni egy generált azonosítóval rendelkező entitást, és belefoglalni azt a sok-sok társításba ugyanabban a tranzakcióban.

Valójában több tranzakciót kell használnunk:

// Először hozza létre a filmet val film = tranzakció {StarWarsFilm.new {name = "Az utolsó Jedik" folytatásId = 8 rendező = "Rian Johnson" r}} // Ezután hozza létre a színészt val aktor = tranzakció {Actor.new {utónév = "Százszorszép" vezetéknév = "Ridley"}} // Végül kapcsolja össze a két tranzakciót {film.actors = SizedCollection (listOf (színész))}

Itt három különböző tranzakciót használtunk a kényelem érdekében. Kettő azonban elegendő lett volna.

9. Következtetés

Ebben a cikkben alapos áttekintést adtunk a Kotlin Exposed keretrendszeréről. További információkat és példákat az Exposed wiki tartalmaz.

Mindezen példák és kódrészletek megvalósítása megtalálható a GitHub projektben.