Vodič za okvir izloženog Kotlina

1. Uvod

U ovom ćemo uputstvu pogledati kako postaviti upit za relacijsku bazu podataka pomoću Izloženo.

Izložena je biblioteka otvorenog koda (licenca Apache) koju je razvio JetBrains, a koja pruža idiomatični Kotlin API za neke implementacije relacijskih baza podataka, istodobno izravnavajući razlike među dobavljačima baza podataka.

Izloženi se može koristiti i kao DSL visoke razine preko SQL-a i kao lagani ORM (objektno-relacijsko mapiranje). Stoga ćemo tijekom ovog vodiča pokriti obje uporabe.

2. Izloženo postavljanje okvira

Izloženo još nije na Maven Central, pa moramo koristiti namjensko spremište:

  izloženo izloženo //dl.bintray.com/kotlin/exposed 

Zatim možemo uključiti knjižnicu:

 izloženi izloženi 0.10.4 

Također, u sljedećim odjeljcima prikazat ćemo primjere korištenja baze podataka H2 u memoriji:

 com.h2data baza podataka h2 1.4.197 

Najnoviju verziju Exposed na Bintrayu možemo pronaći, a najnoviju verziju H2 na Maven Central.

3. Povezivanje s bazom podataka

Veze baze podataka definiramo s Baza podataka razred:

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

Također možemo odrediti a korisnik i a zaporka kao imenovani parametri:

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

Imajte na umu da pozivanje Spojiti ne uspostavlja vezu s DB odmah. Samo sprema parametre veze za kasnije.

3.1. Dodatni parametri

Ako trebamo navesti druge parametre veze, upotrijebit ćemo različito preopterećenje Spojiti metoda koja nam daje potpunu kontrolu nad akvizicijom veze baze podataka:

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

Ova verzija Spojiti zahtijeva parametar zatvaranja. Izloženi poziva zatvaranje kad god mu treba nova veza s bazom podataka.

3.2. Korištenje a Izvor podataka

Ako se umjesto toga povežemo s bazom podataka pomoću a Izvor podataka, kao što je obično slučaj u poslovnim aplikacijama (npr. da bismo imali koristi od spajanja veza), možemo koristiti odgovarajuće Spojiti preopterećenje:

Database.connect (izvor podataka)

4. Otvaranje transakcije

Svaka operacija baze podataka u Izloženom treba aktivnu transakciju.

The transakcija metoda zatvara i poziva ga aktivnom transakcijom:

transakcija {// Do cool things}

The transakcija vraća sve što zatvaranje vrati. Zatim, Izloženo automatski zatvara transakciju kada se izvršavanje bloka završava.

4.1. Obvezivanje i vraćanje

Kada transakcija blok se uspješno vraća, Izloženo izvršava transakciju. Kada, umjesto toga, zatvaranje izađe izbacivanjem iznimke, okvir vraća transakciju.

Također možemo ručno izvršiti ili vratiti transakciju. Zatvaranje koje pružamo transakcija je zapravo instanca Transakcija razred zahvaljujući Kotlinovoj magiji.

Dakle, imamo a počiniti i a vraćanje dostupna metoda:

transakcija {// Napravite neke stvari commit () // Napravite druge stvari}

4.2. Izvještaji o evidentiranju

Tijekom učenja okvira ili ispravljanja pogrešaka, moglo bi nam biti korisno pregledati SQL izraze i upite koje Exposed šalje u bazu podataka.

Takav zapisnik lako možemo dodati aktivnoj transakciji:

transakcija {addLogger (StdOutSqlLogger) // Učiniti stvari}

5. Definiranje tablica

Obično u programu Exposed ne radimo sa sirovim SQL nizovima i imenima. Umjesto toga, definiramo tablice, stupce, ključeve, odnose itd., Koristeći DSL visoke razine.

Svaku tablicu predstavljamo primjerom Stol razred:

objekt StarWarsFilms: Tablica ()

Izloženo automatski izračunava naziv tablice iz naziva klase, ali možemo pružiti i eksplicitno ime:

objekt StarWarsFilms: Tablica ("STAR_WARS_FILMS")

5.1. Stupci

Tablica je besmislena bez stupaca. Stupce definiramo kao svojstva klase tablice:

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

Vrste smo izostavili zbog kratkoće, jer ih Kotlin može zaključiti umjesto nas. Svejedno, svaki je stupac tipa Stupac i ima ime, tip i moguće parametre tipa.

5.2. Primarni ključevi

Kao što možemo vidjeti iz primjera u prethodnom odjeljku, indekse i primarne ključeve možemo lako definirati pomoću fluidnog API-ja.

Međutim, za uobičajeni slučaj tablice s cjelobrojnim primarnim ključem, Exposed nudi klase IntIdTable i LongIdTable koji definiraju ključ za nas:

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

Tu je i UUIDTable; nadalje, vlastite varijante možemo definirati potklasiranjem IdTable.

5.3. Strani ključevi

Strane ključeve lako je uvesti. Također imamo koristi od statičkog tipkanja jer se uvijek pozivamo na svojstva koja su poznata u vrijeme sastavljanja.

Pretpostavimo da želimo pratiti imena glumaca koji igraju u svakom filmu:

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

Da biste izbjegli pisanje vrste stupca (u ovom slučaju, cijeli broj) kada se može izvesti iz referenciranog stupca, možemo koristiti referenca metoda kao stenografija:

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

Ako se referenca odnosi na primarni ključ, možemo izostaviti ime stupca:

val filmId = referenca ("film_id", StarWarsFilms)

5.4. Izrada tablica

Tablice kao što je gore definirano možemo kreirati programski:

transakcija {SchemaUtils.create (StarWarsFilms, Igrači) // Uradi stvari}

Tablice se izrađuju samo ako već ne postoje. Međutim, nema podrške za migracije baze podataka.

6. Upiti

Nakon što definiramo neke klase tablica kao što smo pokazali u prethodnim odjeljcima, možemo bazu podataka izdavati upite pomoću funkcija proširenja koje pruža okvir.

6.1. Odaberi sve

Za izdvajanje podataka iz baze podataka koristimo Upit objekti izgrađeni iz klasa tablica. Najjednostavniji je upit koji vraća sve retke zadane tablice:

val upit = StarWarsFilms.selectAll ()

Upit je Iterable, pa podržava za svakoga:

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

Parametar zatvaranja, implicitno pozvan to u gornjem primjeru je primjer datoteke RezultatRed razred. Možemo ga vidjeti kao kartu koja je označena stupcem.

6.2. Odabir podskupa stupaca

Također možemo odabrati podskup stupaca tablice, tj. Izvesti projekciju pomoću kriška metoda:

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

Koristimo kriška da primijenite funkciju i na stupac:

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

Često se pri korištenju agregatnih funkcija poput računati i prosj, trebat će nam grupa po klauzuli u upitu. O grupi ćemo razgovarati u odjeljku 6.5.

6.3. Filtriranje izraza gdje

Izloženo sadrži posvećeni DSL za gdje izrazi, koji se koriste za filtriranje upita i drugih vrsta izjava. Ovo je mini jezik zasnovan na svojstvima stupaca s kojima smo se ranije susreli i nizu logičkih operatora.

Ovo je izraz gdje:

{(StarWarsFilms.director poput "J.J.%") i (StarWarsFilms.sequelId eq 7)}

Njegov je tip složen; to je podrazred od SqlExpressionBuilder, koji definira operatore kao što su poput, eq i. Kao što vidimo, to je niz usporedbi kombiniranih zajedno s i i ili operatora.

Takav izraz možemo prenijeti na Odaberi metoda, koja opet vraća upit:

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

Zahvaljujući zaključivanju tipa, ne trebamo pisati složeni tip izraza where kada je izravno proslijeđen u Odaberi metoda kao u gornjem primjeru.

Budući da su tamo gdje su izrazi Kotlin objekti, ne postoje posebne odredbe za parametre upita. Jednostavno koristimo varijable:

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

6.4. Napredno filtriranje

The Upit predmeti koje je vratio Odaberi a njegove inačice imaju niz metoda kojima se možemo poslužiti za pročišćavanje upita.

Na primjer, možda bismo htjeli izuzeti dvostruke retke:

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

Ili bismo možda htjeli vratiti samo podskup redaka, na primjer prilikom paginiranja rezultata za korisničko sučelje:

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

Ove metode vraćaju novo Upit, tako da ih možemo lako povezati lancima.

6.5. NarudžbaPo i SkupinaPo

The Upit. narudžbaBy metoda prihvaća popis stupaca preslikanih u SortOrder vrijednost koja pokazuje treba li sortiranje rasti ili silazno:

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

Dok se grupiranje po jednom ili više stupaca, korisno posebno kada se koriste agregatne funkcije (vidi odjeljak 6.2.), Postiže pomoću grupaBy metoda:

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

6.6. Pridružuje se

Pridruživanja su nedvojbeno jedno od prodajnih mjesta relacijskih baza podataka. U najjednostavnijim slučajevima, kada imamo strani ključ i nemamo uvjete pridruživanja, možemo koristiti jedan od ugrađenih operatora pridruživanja:

(StarWarsFilms innerPrijavite se igračima) .selectAll ()

Ovdje smo pokazali unutarnjiPridružite se, ali također imamo lijevo, desno i poprečno spajanje dostupno s istim principom.

Zatim možemo dodati uvjete pridruživanja izrazom where; na primjer, ako nema stranog ključa i moramo izričito izvršiti spajanje:

(StarWarsFilms innerJoin Players) .select {StarWarsFilms.sequelId eq Players.sequelId}

U općenitom slučaju, puni oblik pridruživanja je sljedeći:

val complexJoin = Pridruži se (StarWarsFilms, Igrači, onColumn = StarWarsFilms.sequelId, otherColumn = Players.sequelId, joinType = JoinType.INNER, AdditionalConstraint = {StarWarsFilms.sequelId eq 8}) complexJoin.selectAll ()

6.7. Aliasing

Zahvaljujući mapiranju imena stupaca u svojstva, ne treba nam nikakvo udruživanje u tipičnom spajanju, čak i kada se slučajno imaju isti nazivi stupaca:

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

Zapravo, u gornjem primjeru, StarWarsFilms.sequelId i Igrači.dalje ID su različiti stupci.

Međutim, kada se ista tablica pojavi više puta u upitu, možda bismo joj željeli dati nadimak. Za to koristimo alias funkcija:

val nastavak = StarWarsFilms.alias ("nastavak")

Tada možemo koristiti alias poput tablice:

Pridružite se (StarWarsFilms, nastavak, AdditionalConstraint = {nastavak [StarWarsFilms.sequelId] eq StarWarsFilms.sequelId + 1}). SelectAll (). ForEach {assertEquals (it [nastavak [StarWarsFilms.sequelId]], to [StarWarsFilms.sequel )}

U gornjem primjeru možemo vidjeti da nastavak alias je tablica koja sudjeluje u pridruživanju. Kada želimo pristupiti jednom od njegovih stupaca, kao ključ koristimo stupac alias tablice:

nastavak [StarWarsFilms.sequelId]

7. Izjave

Sad kad smo vidjeli kako upitivati ​​bazu podataka, pogledajmo kako se izvode DML izrazi.

7.1. Umetanje podataka

Da bismo umetnuli podatke, pozivamo jednu od varijanti umetnuti funkcija. Sve se inačice zatvaraju:

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

Dva su značajna predmeta koja su uključena u prethodno zatvaranje:

  • ovaj (samo zatvaranje) je instanca StarWarsFilms razred; zato stupcima koji su svojstva možemo pristupiti pod njihovim nekvalificiranim nazivom
  • to (parametar zatvaranja) je InsertStatement; jat je struktura nalik mapi s utorom za svaki stupac za umetanje

7.2. Izdvajanje vrijednosti stupca s automatskim povećanjem

Kada imamo izjavu za umetanje s automatski generiranim stupcima (obično automatsko povećanje ili sekvence), možda ćemo htjeti dobiti generirane vrijednosti.

U tipičnom slučaju imamo samo jednu generiranu vrijednost i zovemo insertAndGetId:

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

Ako imamo više od jedne generirane vrijednosti, možemo ih pročitati po imenu:

val insert = StarWarsFilms.insert {it [name] = "Sila se budi" it [sequelId] = 7 it [director] = "J.J. Abrams"} assertEquals (2, umetni [StarWarsFilms.id] ?. vrijednost)

7.3. Ažuriranje podataka

Sada možemo koristiti ono što smo naučili o upitima i umetanju za ažuriranje postojećih podataka u bazi podataka. Zapravo, jednostavno ažuriranje izgleda kao kombinacija odabira s umetkom:

StarWarsFilms.update ({StarWarsFilms.sequelId eq 8}) {it [name] = "Epizoda VIII - Posljednji Jedi"}

Možemo vidjeti upotrebu izraza where u kombinaciji s UpdateStatement zatvaranje. Zapravo, UpdateStatement i InsertStatement dijele većinu API-ja i logike kroz zajedničku superklasu, UpdateBuilder, koji pruža mogućnost postavljanja vrijednosti stupca pomoću idiomatskih uglatih zagrada.

Kad trebamo ažurirati stupac izračunavanjem nove vrijednosti iz stare vrijednosti, koristimo SqlExpressionBuilder:

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

Ovo je objekt koji pruža infiksne operatore (poput plus, minus i tako dalje) koje možemo koristiti za izradu uputa za ažuriranje.

7.4. Brisanje podataka

Konačno, podatke možemo izbrisati pomoću deleteWhere metoda:

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

8. DAO API, lagani ORM

Do sada smo koristili Exposed za izravno mapiranje operacija na objektima Kotlin u SQL upite i izraze. Svaka metoda poziva kao umetnuti, ažurirati, odabrati i tako dalje rezultira time da se SQL niz odmah šalje u bazu podataka.

Međutim, Exposed također ima DAO API više razine koji predstavlja jednostavan ORM. Krenimo sada u to.

8.1. Entiteti

U prethodnim smo odjeljcima koristili klase za predstavljanje tablica baze podataka i izražavanje operacija nad njima, koristeći statičke metode.

Pomaknuvši se korak dalje, možemo definirati entitete na temelju tih klasa tablica, gdje svaka instanca entiteta predstavlja red baze podataka:

klasa StarWarsFilm (id: EntityID): Entity (id) {prateći objekt: EntityClass (StarWarsFilms) var sequelId by StarWarsFilms.sequelId var name by StarWarsFilms.name var director by StarWarsFilms.director}

Ajmo sada analizirati gornju definiciju dio po dio.

U prvom retku možemo vidjeti da je entitet klasa koja se proteže Entitet. Ima ID s određenom vrstom, u ovom slučaju, Int.

klasa StarWarsFilm (id: EntityID): Entity (id) {

Tada nailazimo na definiciju popratnog objekta. Prateći objekt predstavlja klasu entiteta, odnosno statičke metapodatke koji definiraju entitet i operacije koje na njemu možemo izvršiti.

Nadalje, u deklaraciji popratnog objekta povezujemo entitet, StarWarsFilm - jednine, jer predstavlja jedan red za stol, StarWarsFilms - množina, jer predstavlja zbirku svih redaka.

popratni objekt: EntityClass (StarWarsFilms)

Napokon, imamo svojstva, implementirana kao delegati svojstava u odgovarajuće stupce tablice.

var sequelId od StarWarsFilms.sequelId var ime od StarWarsFilms.name var direktor od StarWarsFilms.director

Imajte na umu da smo prethodno deklarirali stupce s val jer su nepromjenjivi metapodaci. Sada umjesto toga deklariramo svojstva entiteta sa var, jer su promjenjivi utora u redu baze podataka.

8.2. Umetanje podataka

Da bismo umetnuli redak u tablicu, jednostavno kreiramo novu instancu naše klase entiteta koristeći statičku tvorničku metodu novi u transakciji:

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

Imajte na umu da se operacije protiv baze podataka izvode lijeno; izdaju se samo kad topla predmemorija ispire se. Za usporedbu, Hibernate toplu predmemoriju naziva a sjednica.

To se automatski događa kada je to potrebno; npr. kada prvi put čitamo generirani identifikator, Exposed tiho izvršava insert naredbu:

assertEquals (1, theLastJedi.id.value) // Čitanje ID-a uzrokuje ispiranje

Usporedite ovo ponašanje s umetnuti metoda iz odjeljka 7.1., koja odmah izdaje izjavu protiv baze podataka. Ovdje radimo na višoj razini apstrakcije.

8.3. Ažuriranje i brisanje objekata

Da bismo ažurirali redak, jednostavno mu dodijelimo svojstva:

theLastJedi.name = "Epizoda VIII - Posljednji Jedi"

Dok za brisanje objekta koji zovemo izbrisati na tome:

theLastJedi.delete ()

Kao i sa novi, ažuriranje i operacije izvode se lijeno.

Ažuriranja i brisanja mogu se izvoditi samo na prethodno učitanom objektu. Ne postoji API za masovna ažuriranja i brisanja. Umjesto toga, moramo koristiti API niže razine koji smo vidjeli u odjeljku 7. Ipak, dva API-ja mogu se koristiti zajedno u istoj transakciji.

8.4. Upit

Pomoću DAO API-a možemo izvršiti tri vrste upita.

Za učitavanje svih objekata bez uvjeta koristimo statičku metodu svi:

val filmovi = StarWarsFilm.all ()

Da bismo učitali jedan objekt pomoću ID-a koji zovemo findById:

val theLastJedi = StarWarsFilm.findById (1)

Ako nema predmeta s tim ID-om, findById vraća se null.

Konačno, u općenitom slučaju koristimo pronaći s izrazom where:

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

8.5. Udruge Mnogo-prema-jednom

Baš kao što su pridruživanja važna značajka relacijskih baza podataka, mapiranje spajanja na reference važan je aspekt ORM-a. Pa, pogledajmo što Exposed nudi.

Pretpostavimo da želimo pratiti ocjenu svakog filma od strane korisnika. Prvo definiramo dvije dodatne tablice:

objekt Korisnici: IntIdTable () {val name = varchar ("name", 50)} objekt UserRatings: IntIdTable () {val value = long ("value") val film = reference ("film", StarWarsFilms) val user = reference ("korisnik", korisnici)}

Zatim ćemo napisati odgovarajuće entitete. Izostavimo Korisnik entitet, koji je trivijalan, i prijeđite ravno na Korisnička ocijena razred:

klasa UserRating (id: EntityID): IntEntity (id) {prateći objekt: IntEntityClass (UserRatings) var vrijednost od UserRatings.value var film od StarWarsFilm referencedOn UserRatings.film var korisnik od User referencedOn UserRatings.user}

Konkretno, imajte na umu referencedOn poziv metode infix na svojstvima koja predstavljaju asocijacije. Uzorak je sljedeći: a var deklaracija, po referencirani entitet, referencedOn referentni stupac.

Ovako deklarirana svojstva ponašaju se poput uobičajenih svojstava, ali njihova je vrijednost pridruženi objekt:

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

8.6. Fakultativne udruge

Povezivanja koja smo vidjeli u prethodnom odjeljku su obavezna, odnosno uvijek moramo navesti vrijednost.

Ako želimo neobaveznu asocijaciju, prvo moramo proglasiti stupac nulabilnim u tablici:

val korisnik = referenca ("korisnik", Korisnici) .nullable ()

Zatim ćemo upotrijebiti optionalReferencedOn umjesto referencedOn u entitetu:

var korisnik od strane User optionalReferencedOn UserRatings.user

Na taj način, korisnik svojstvo će biti poništeno.

8.7. Udruge jedan-prema-mnogima

Možda bismo željeli mapirati i suprotnu stranu udruge. Ocjena se odnosi na film, to je ono što modeliramo u bazi s inozemnim ključem; shodno tome, film ima brojne ocjene.

Da bismo mapirali ocjene filma, jednostavno dodamo svojstvo na "jednu" stranu udruge, odnosno filmsku cjelinu u našem primjeru:

klasa StarWarsFilm (id: EntityID): Entity (id) {// Ostala svojstva su izbrisala ocjene valua po UserRating refererOn UserRatings.film}

Uzorak je sličan obrascu odnosa više-prema-jednom, ali koristi uputniciOn. Tako definirano svojstvo je Iterable, tako da ga možemo prijeći za svakoga:

theLastJedi.ratings.forEach {...}

Imajte na umu da smo, za razliku od uobičajenih svojstava, definirali ocjene s val. Doista, svojstvo je nepromjenjivo, možemo ga samo pročitati.

Vrijednost svojstva također nema API za mutaciju. Dakle, da bismo dodali novu ocjenu, moramo je stvoriti s referencom na film:

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

Zatim, film ocjene Popis će sadržavati novo dodanu ocjenu.

8.8. Udruge Mnogo-Mnogo

U nekim će nam slučajevima možda trebati udruživanje mnogo-do-mnogih. Recimo da želimo dodati referencu an Glumci stol do StarWarsFilm razred:

glumci objekta: IntIdTable () {val ime = varchar ("ime", 50) val prezime = varchar ("prezime", 50)} klasa glumac (id: EntityID): IntEntity (id) {prateći objekt: IntEntityClass (glumci) var ime po Actors.firstname var prezime po Actors.lastname}

Nakon definiranja tablice i entiteta, trebamo još jednu tablicu koja će predstavljati asocijaciju:

objekt StarWarsFilmActors: Tablica () {val starWarsFilm = referenca ("starWarsFilm", StarWarsFilms) .primaryKey (0) val glumac = referenca ("glumac", Glumci) .primaryKey (1)}

Tablica ima dva stupca koji su istovremeno strani ključevi i koji također čine složeni primarni ključ.

Napokon, možemo povezati tablicu pridruživanja s StarWarsFilm entitet:

klasa StarWarsFilm (id: EntityID): IntEntity (id) {prateći objekt: IntEntityClass (StarWarsFilms) // Druga svojstva koja je glumac izbacio izvođača putem StarWarsFilmActors}

U vrijeme pisanja ovog članka nije moguće stvoriti entitet s generiranim identifikatorom i uključiti ga u udrugu više-do-više u istoj transakciji.

Zapravo moramo koristiti više transakcija:

// Prvo stvorimo film val film = transakcija {StarWarsFilm.new {name = "The Last Jedi" sequelId = 8 director = "Rian Johnson" r}} // Zatim, stvorimo glumac val glumac = transakcija {Actor.new {firstname = "Daisy" lastname = "Ridley"}} // Napokon, povežite dvije transakcije {film.actors = SizedCollection (listOf (glumac))}

Ovdje smo radi praktičnosti koristili tri različite transakcije. Međutim, dva bi bila dovoljna.

9. Zaključak

U ovom smo članku dali temeljit pregled Izloženog okvira za Kotlin. Za dodatne informacije i primjere pogledajte izloženi wiki.

Provedbu svih ovih primjera i isječaka koda možete pronaći u projektu GitHub.