Përshëndetje, Habr!
Ne pohojme të hetojmë temën dhe , përfshirë në nivelin e bazave të të dhënave. Sot ju ofrojmë një lexim mbi arsyen se pse kur projektoni aplikacione të mëdha, struktura e bazës së të dhënave, dhe jo kodi Java, duhet të ketë rëndësi vendimtare, si është e realizueshme kjo dhe cilat janë përjashtimet nga ky rregull.
Në këtë artikull të vonuar, do të shpjegoj arsyen pse mendoj se në praktikisht të gjitha rastet, modeli i të dhënave në aplikacion duhet të projektohet "duke u nisur nga baza e të dhënave", dhe jo "duke u nisur nga mundësitë e Java" (ose ndonjë gjuhe tjetër klienti me të cilën po punoni). Duke zgjedhur qasjen e dytë, ju filloni një rrugë të gjatë vuajtjesh sapo projekti juaj fillon të rritet.
Artikulli është shkruar mbi motivin e , që u bë në Stack Overflow.
Diskutimet interesante në reddit në seksionet dhe .
Gjenerimi i kodit
Sa shumë u befasova kur zbulova se ekziston një grup aq i vogël përdoruesish, të cilët, pasi u njohën me jOOQ, u shqetësuan nga fakti se në punën me jOOQ mbështetet seriozisht në gjenerimin e kodit. Askush nuk ju pengon të përdorni jOOQ ashtu si e shihni të arsyeshme dhe nuk ju detyron të përdorni gjenerimin e kodit. Por në mënyrë default (ashtu siç përshkruhet në manual), puna me jOOQ ndodh kështu: filloni me (trashëguar) schemën e bazës së të dhënave, kryeni inxhinierinë e saj të prapmë me ndihmën e gjeneratorit të kodit jOOQ, për të marrë një grup klasash që përfaqësojnë tabelat tuaja, dhe më pas shkruani pyetje të sigurta për tipin për këto tabela:
for (Record2 record : DSL.using(configuration)
// ^^^^^^^^^^^^^^^^^^^^^^^ Informacioni mbi tipet është nxjerrë në
// bazë të kodit të gjeneruar, i cili referohet në kushtin e dhënë
// më poshtë SELECT
.select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
// vvvvv ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ emrat e gjeneruar
.from(ACTOR)
.orderBy(1, 2)) {
// ...
}Kodi gjenerohet ose manualisht jashtë ndërtimit, ose manualisht çdo herë kur ndodh ndërtimi. Për shembull, një rigjenerim i tillë mund të ndodhë menjëherë pas .
Gjenerimi i kodit burimor
Me kĂ«to qasje ndaj gjenerimit tĂ« kodit â manuale dhe automatike â lidhen filozofi tĂ« ndryshme, avantazhe dhe disavantazhe, tĂ« cilat nuk do tâi diskutoj nĂ« detaje nĂ« kĂ«tĂ« artikull. Por, nĂ« pĂ«rgjithĂ«si, e gjithĂ« thelbi i kodit tĂ« gjeneruar Ă«shtĂ« se ai lejon tĂ« riprodhohet nĂ« Java ajo "e vĂ«rtetĂ«", qĂ« e pranojmĂ« si tĂ« dhĂ«nĂ«, qoftĂ« brenda sistemit tonĂ«, qoftĂ« jashtĂ« tij. NĂ« njĂ«farĂ« mĂ«nyre, tĂ« njĂ«jtĂ«n gjĂ« bĂ«jnĂ« kompilet, tĂ« cilĂ«t gjenerojnĂ« kodin bajt, kodin makinerik ose ndonjĂ« formĂ« tjetĂ«r tĂ« kodit mbi bazĂ«n e burimeve â ne marrim njĂ« pĂ«rfaqĂ«sim tĂ« "e vĂ«rtetĂ«s" tonĂ« nĂ« njĂ« gjuhĂ« tjetĂ«r, pavarĂ«sisht shkakut tĂ« veçantĂ«.
Ekzistojnë shumë të tillë gjenerues kodesh. Për shembull, . Parimi gjithmonë është i njëjtë:
- Ekziston njĂ« e vĂ«rtetĂ« (brendshme ose jashtme) â pĂ«r shembull, specifikimi, modeli i tĂ« dhĂ«nave, etj.
- Na nevojitet një përfaqësim lokal i kësaj të vërtete në gjuhën tonë programore.
Dhe Ă«shtĂ« gjithmonĂ« e arsyeshme tĂ« gjenerohet njĂ« pĂ«rfaqĂ«sim i tillĂ« â pĂ«r tĂ« evituar qĂ«llimin e tepĂ«rt.
Ofertues të llojeve dhe përpunimi i annotimeve
PĂ«r t'u vĂ«nĂ« nĂ« dukje: njĂ« tjetĂ«r, mĂ« modern dhe specifik qasje ndaj gjenerimit tĂ« kodit pĂ«r jOOQ lidhet me pĂ«rdorimin e ofertuesve tĂ« llojeve, . NĂ« kĂ«tĂ« rast, kodi gjenerohet nga kompajleri, pikĂ«risht nĂ« fazĂ«n e kompilimimit. NĂ« formĂ«n e burimeve njĂ« kod i tillĂ« nĂ« parim nuk ekziston. NĂ« Java ekzistojnĂ« mjete tĂ« ngjashme, megjithĂ«se jo aq elegante â kĂ«to janĂ« procesorĂ«t e annotimeve, pĂ«r shembull, .
Në një farë kuptimi, këtu ndodhin të njëjtat gjëra si në rastin e parë, përveç:
- Nuk e shihni kodin e gjeneruar (ndoshta kjo situatë disa njerëzve u duket jo aq e frikshme?)
- Duhet tĂ« garantoni qĂ« llojet mund tĂ« ofrohen, dmth, "e vĂ«rteta" gjithmonĂ« duhet tĂ« jetĂ« e disponueshme. Kjo Ă«shtĂ« e lehtĂ« nĂ« rastin e Lombok, i cili annoton âe vĂ«rtetĂ«nâ. MĂ« pak e thjeshtĂ« me modelet e bazave tĂ« tĂ« dhĂ«nave, puna e tĂ« cilave varet nga njĂ« lidhje e drejtpĂ«rdrejtĂ« e vazhdueshme.
Cila është problemi me gjenerimin e kodit?
Përveç një pyetje të hollë rreth mënyrës më të mirë për të filluar gjenerimin e kodit - në mënyrë manuale apo automatikisht, duhet të përmendim gjithashtu se ka njerëz që mendojnë se gjenerimi i kodit nuk është i nevojshëm fare. Justifikimi i një pikëpamjeje të tillë, të cilin e kam hasur shpesh, është se atëherë është e vështirë të konfigurosh cilindrin e ndërtimit. Po, me të vërtetë është e vështirë. Ka shpenzime shtesë infrastrukturore. Nëse sapo po filloni të punoni me një produkt të caktuar (qoftë jOOQ, JAXB, Hibernate, etj.), koha e nevojshme për të konfiguruar mjedisin e punës është një kohë që do të donit ta kalonit duke studiuar vetë API-n, për të nxjerrë më vonë vlerë prej saj.
NĂ«se shpenzimet janĂ« shumĂ« tĂ« mĂ«dha pĂ«r tĂ« kuptuar funksionimin e gjeneratorit â atĂ«herĂ« me tĂ« vĂ«rtetĂ« API-ja nuk ka punuar mirĂ« nĂ« pĂ«rdorshmĂ«rinĂ« e gjeneratorit (dhe mĂ« vonĂ« del se edhe konfigurimi i pĂ«rdoruesit nĂ« tĂ« Ă«shtĂ« i komplikuar). LehtĂ«sia e pĂ«rdorimit duhet tĂ« jetĂ« prioriteti mĂ« i lartĂ« pĂ«r çdo API tĂ« tillĂ«. Por ky Ă«shtĂ« vetĂ«m njĂ« argument kundĂ«r gjenerimit tĂ« kodit. NĂ« tĂ« tjerat, Ă«shtĂ« absolutisht e nevojshme tĂ« shkruhet manualisht prezantimi lokal i sĂ« vĂ«rtetĂ«s sĂ« brendshme ose tĂ« jashtme.
Shumë do të thonë se nuk kanë kohë për të bërë të gjitha këto. Ata kanë afate për produktin e tyre Super. Diku më vonë do ta rregullojmë cilindrin e ndërtimit, do të kemi kohë. Unë iu përgjigjem atyre:

,
Por në Hibernate / JPA është kaq e lehtë të shkruash kod "nën Java".
Në të vërtetë. Për Hibernate dhe përdoruesit e tij, kjo është njëherësh një bekim dhe një mallkim. Në Hibernate mund të shkruash thjesht disa entitete, kështu:
@Entity
class Book {
@Id
int id;
String title;
}Dhe pothuajse çdo gjë është gati. Tani detyra e Hibernate është të gjenerojë "detajet" komplekse të asaj se si do të përcaktohet me të vërtetë kjo entitet në DDL-në e "dialektit" tuaj SQL:
CREATE TABLE book (
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
title VARCHAR(50),
CONSTRAINT pk_book PRIMARY KEY (id)
);
CREATE INDEX i_book_title ON book (title);... dhe fillojmë të përshkojmë aplikacionin. Vërtet një mundësi e shkëlqyer, për të filluar shpejt dhe për të provuar gjëra të ndryshme.
Megjithatë, ndaluni një çast. Kam gënjyer.
- Por a do ta aplikojë Hibernate definicionin e këtij çelësi primar të emëruar?
- A do tĂ« krijojĂ« Hibernate indeksin nĂ« TITLE? â unĂ« e di saktĂ«sisht se do na nevojitet.
- A do ta bëjë Hibernate këtë çelës identifikues në Specifikimin e Identitetit?
Ndoshta jo. Nëse po e zhvilloni projektin tuaj nga e para, gjithmonë është e dobishme të hiqni bazën e të dhënave të vjetër dhe të krijoni një të re, sa herë që të shtoni anotacionet e nevojshme. Kështu, entiteti Book në fund do të duket si:
@Entity
@Table(name = "book", indexes = {
@Index(name = "i_book_title", columnList = "title")
})
class Book {
@Id
@GeneratedValue(strategy = IDENTITY)
int id;
String title;
}
Super. Rinisni nga fillimi. Edhe kësaj here, në një rast të tillë, do të jetë shumë e lehtë në fillim.
Por më vonë do t'ju duhet të paguani për këtë.
Për ose më vonë do të duhet të kaloni në prodhim. Pikërisht atëherë ky model do të ndalojë së funksionuari. Sepse:
Në prodhim nuk do të jetë e mundur, sipas nevojës, të hiqni bazën e të dhënave të vjetër dhe të filloni gjithçka nga e para. Baza juaj e të dhënave do të bëhet hereditar.
Që nga tani e tutje do t'ju duhet të shkruani . Por çfarë do të ndodhë në këtë rast me entitetet tuaja? Ju mund të adaptoni ato manualisht (dhe kështu do të dyfishoni punën tuaj), ose mund të kërkoni nga Hibernate t'i gjenerojë përsëri për ju (sa të mëdha janë shanset që ato të jenë siç e prisni?) Në çdo rast, ju humbni.
Pra, sa herë që kaloni në prodhim, ju nevojiten patches të nxehta. Dhe ato duhet të dalin në prodhim shumë shpejt. Sepse ju nuk u përgatitët dhe nuk organizuat një konvej për migrimet tuaja, ju gjithçka do ta patçoni. Dhe pastaj nuk do të keni kohë ta bëni gjithçka siç duhet. Dhe e akuzoni Hibernate, sepse gjithmonë është faji i dikujt tjetër, jo ju...
Në vend të kësaj, që nga fillimi mund të bëni gjithçka krejt ndryshe. Për shembull, ndoshta të vendosni rrota të rrumbullakëta në biçikletë.
Së pari baza e të dhënave.
E vĂ«rteta e vĂ«rtetĂ« nĂ« skemĂ«n e bazĂ«s tuaj tĂ« tĂ« dhĂ«nave dhe "sovraniteti" mbi tĂ« qĂ«ndron brenda bazĂ«s sĂ« tĂ« dhĂ«nave. Skema pĂ«rcaktohet vetĂ«m brenda vetĂ« bazĂ«s sĂ« tĂ« dhĂ«nave dhe askund tjetĂ«r, dhe çdo klient ka njĂ« kopje tĂ« kĂ«saj skeme, kĂ«shtu qĂ« Ă«shtĂ« krejt e arsyeshme tĂ« impononi ruajtjen e skemĂ«s dhe integritetit tĂ« saj, duke bĂ«rĂ« kĂ«tĂ« direkt nĂ« bazĂ«n e tĂ« dhĂ«nave â aty ku ruhet informacioni.
Kjo Ă«shtĂ« njĂ« urtĂ«si e vjetĂ«r, madje e vjetĂ«r. ĂelĂ«sat e parĂ« dhe unikĂ« janĂ« tĂ« mirĂ«. ĂelĂ«sat e jashtĂ«m â janĂ« tĂ« mirĂ«. Verifikimi i kufizimeve â Ă«shtĂ« i mirĂ«. â janĂ« tĂ« mira.
Dhe, kjo nuk është gjithçka. Për shembull, duke përdorur Oracle, ndoshta do të dëshironi të specifikoni:
- Në cilin hapësirë tabellash ndodhet tabela juaj
- Cili është vlerë PCTFREE
- Cili është madhësia e caches në sekuencën tuaj (pas identifikuesit)
Ndoshta e gjitha kjo nuk ka rĂ«ndĂ«si nĂ« sistemet e vogla, por nuk Ă«shtĂ« e nevojshme tĂ« prisni kalimin nĂ« fushĂ«n e 'tĂ« dhĂ«nave tĂ« mĂ«dha' â mund tĂ« filloni tĂ« pĂ«rfitoni nga optimizimet e ruajtjes sĂ« tĂ« dhĂ«nave qĂ« ofrohen nga ofruesi, si ato tĂ« pĂ«rmendura mĂ« sipĂ«r, edhe mĂ« herĂ«t. AsnjĂ« prej ORM-ve qĂ« kam parĂ« (pĂ«rfshirĂ« jOOQ) nuk ofron qasje nĂ« tĂ« gjithĂ« grupin e mundĂ«sive DDL qĂ« mund tĂ« dĂ«shironi tĂ« pĂ«rdorni nĂ« bazĂ«n tuaj tĂ« tĂ« dhĂ«nave. ORM-tĂ« ofrojnĂ« disa mjete qĂ« ndihmojnĂ« nĂ« shkrimin e DDL.
Por, nĂ« fund tĂ« fundit, njĂ« skemĂ« e mirĂ«projektuar shkruhet manualisht nĂ« DDL. Ădo DDL e gjeneruar Ă«shtĂ« vetĂ«m njĂ« aproximim i saj.
ĂfarĂ« ndodh me modelin e klientit?
Siç u përmend më parë, në klient do t'ju duhet një kopje e skemës së bazës suaj të të dhënave, një pamje e klientit. E tepërt për të përmendur se kjo pamje e klientit duhet të jetë e sinkronizuar me modelin e vërtetë. Si t'ia arrini më së miri kësaj? Me ndihmën e një gjeneratori kodi.
Të gjitha bazat e të dhënave ofrojnë metainformacionin e tyre përmes SQL. Ja si të merrni të gjitha tabelat nga baza juaj e të dhënave në dialekte të ndryshme SQL:
-- H2, HSQLDB, MySQL, PostgreSQL, SQL Server
SELECT table_schema, table_name
FROM information_schema.tables
-- DB2
SELECT tabschema, tabname
FROM syscat.tables
-- Oracle
SELECT owner, table_name
FROM all_tables
-- SQLite
SELECT name
FROM sqlite_master
-- Teradata
SELECT databasename, tablename
FROM dbc.tables
Këto kërkesa (apo të ngjashme me to, në varësi të faktit nëse duhet të merrni parasysh gjithashtu pamjet, pamjet e materializuara, funksionet me vlerë tabellash) ekzekutohen gjithashtu përmes thirrjes nga JDBC, ose përmes modulit meta jOOQ.
Nga rezultatet e këtyre kërkesave është relativisht e lehtë të gjenerosh çdo pamje klienti të modelit të bazës së të dhënave, pa zakoni se çfarë teknologjie përdorni në klientin tuaj.
- Nëse përdorni JDBC ose Spring, mund të krijoni një grup konstantash string
- Nëse përdorni JPA, mund të gjeneroni vetë entitetet
- Nëse përdorni jOOQ, mund të gjeneroni modelin meta të jOOQ
Në varësi të asaj që ofrohet nga API juaj për klientët (p.sh. jOOQ ose JPA), meta-modeli i gjeneruar mund të jetë me të vërtetë i pasur dhe i plotë. Le të marrim, për shembull, mundësinë e bashkimeve të implicit, , e cila mbështetet në metainformacionin e gjeneruar mbi marrëdhëniet e çelësave të jashtëm, që veprojnë midis tabelave tuaja.
Tani çdo rritje e bazës së të dhënave do të çojë automatikisht në përditësimin e kodit të klientit. Imagjinoni, për shembull:
ALTER TABLE book RENAME COLUMN title TO book_title;A do të donit të bënit këtë punë dy herë? Asnjëherë. Thjesht regjistroni DDL-në, kaloni atë përmes konvejerit tuaj të ndërtimit dhe merrni entitetin e përditësuar:
@Entity
@Table(name = "book", indexes = {
// A e keni menduar këtë?
@Index(name = "i_book_title", columnList = "book_title")
})
class Book {
@Id
@GeneratedValue(strategy = IDENTITY)
int id;
@Column("book_title")
String bookTitle;
}Ose klasa e përditësuar jOOQ. Shumica e ndryshimeve DDL reflektohen gjithashtu në semantike, dhe jo vetëm në sintaksë. Prandaj, ndonjëherë është e dobishme të shihni në kodin e kompiluar se cili kod do të preket (apo mund të preket) nga rritja e bazës suaj të të dhënave.
E vërteta e vetme
PavarĂ«sisht se çfarĂ« teknologjie pĂ«rdorni, gjithmonĂ« ka njĂ« model qĂ« Ă«shtĂ« burimi i vetĂ«m i vĂ«rtetĂ«s pĂ«r njĂ« nĂ«nsisistem tĂ« caktuar â ose, tĂ« paktĂ«n, duhet tĂ« strimcahemi pĂ«r kĂ«tĂ« dhe tĂ« shmangim njĂ« konfuzion tĂ« tillĂ« enterprise ku "e vĂ«rteta" Ă«shtĂ« menjĂ«herĂ« kudo dhe asnjĂ«herĂ«. Gjithçka mund tĂ« jetĂ« shumĂ« mĂ« e thjeshtĂ«. NĂ«se thjesht shkĂ«mbeni skedarĂ« XML me ndonjĂ« sistem tjetĂ«r, thjesht pĂ«rdorni XSD. Shikoni nĂ« meta-modelin INFORMATION_SCHEMA nga jOOQ nĂ« formatin XML:
- XSD është e kuptueshme mirë
- XSD markon mjaft mirë përmbajtjen e XML dhe lejon validimin në të gjitha gjuhët e klientëve
- XSD ka një versionim të mirë dhe ofron një përputhshmëri të avancuar mbrapa
- XSD mund të transformohet në kod Java përmes XJC
Pika e fundit është e rëndësishme. Kur komunikojmë me një sistem të jashtëm përmes mesazhesh XML, duam të jemi të sigurt për vlefshmërinë e mesazheve tona. Kjo është shumë e lehtë të arrihet përmes JAXB, XJC dhe XSD. Do të ishte çmenduri të mendojmë se, duke iu qasur projektimit "Java e parë", ku ne i bëjmë mesazhet tona si objekte Java, ato mund të projektohen në XML dhe të dërgohen për konsum në një sistem tjetër. XML i gjeneruar kështu do të ishte me cilësi shumë të dobët, pa dokumentim, dhe do të ishte i vështirë për t'u zhvilluar. Nëse për një ndërfaqe të tillë ekzistonte një marrëveshje për nivelin e shërbimit (SLA), do ta kishim dështuar menjëherë.
Sinqerisht, kjo është pikërisht ajo që ndodh vazhdimisht me API-të në JSON, por kjo është një histori tjetër, herën tjetër do të ankohem...
Baza të dhënash: është e njëjta gjë.
Kur punoni me baza tĂ« dhĂ«nash, kuptoni se tĂ« gjitha janĂ«, nĂ« thelb, tĂ« ngjashme. NjĂ« bazĂ« zotĂ«ron tĂ« dhĂ«nat e saj dhe duhet tĂ« udhĂ«heqĂ« skemĂ«n. Ădo modifikim qĂ« bĂ«het nĂ« skemĂ« duhet tĂ« implementohet drejtpĂ«rdrejt nĂ« DDL, nĂ« mĂ«nyrĂ« qĂ« burimi i vetĂ«m i sĂ« vĂ«rtetĂ«s tĂ« azhurnohet.
Kur burimi i azhurnohet, të gjithë klientët gjithashtu duhet të azhurnojnë kopjet e tyre të modelit. Disa klientë mund të jenë shkruar në Java duke përdorur jOOQ dhe Hibernate ose JDBC (apo të gjitha njëherësh). Klientë të tjerë mund të jenë shkruar në Perl (u uroj fat), të tjerët - në C#. Nuk ka rëndësi. Modeli kryesor është në bazën e të dhënave. Modelet e gjeneruara përmes ORM zakonisht janë të dobëta, me dokumentim të dobët dhe të vështira për t'u zhvilluar.
Prandaj mos bĂ«ni gabime. Prej fillimit mos bĂ«ni gabime. Punoni nga baza e tĂ« dhĂ«nave. NdĂ«rtoni njĂ« pipeline shpĂ«rndarjeje qĂ« mund tĂ« automatizohet. PĂ«rfshini gjeneruesit e kodit pĂ«r ta bĂ«rĂ« tĂ« lehtĂ« kopjimin e modelit tĂ« bazĂ«s tuaj tĂ« dhĂ«nash dhe shpĂ«rndarjen e tij te klientĂ«t. Dhe ndaloni sĂ« shqetĂ«suari pĂ«r gjeneruesit e kodit. Ata janĂ« tĂ« mirĂ«. Me ta do tĂ« bĂ«heni mĂ« produktivĂ«. VetĂ«m duhet tĂ« shpenzoni pak kohĂ« nĂ« fillim pĂ«r t'i pĂ«rshtatur ato â dhe mĂ« pas ju presin vite produktiviteti tĂ« pĂ«rmirĂ«suar, nga tĂ« cilat do tĂ« formohet historia e projektit tuaj.
Mos e falëndero tani, më vonë.
Shpjegimi
PĂ«r qartĂ«si: Ky artikull nĂ« asnjĂ« mĂ«nyrĂ« nuk propagandon qĂ« modeli i bazĂ«s suaj tĂ« tĂ« dhĂ«nave duhet tĂ« pĂ«rshtatet me gjithĂ« sistemin (pra, fushĂ«n e subjektit, logjikĂ«n e biznesit, etj.). NĂ« kĂ«tĂ« artikull, po flas pĂ«r faktin se kodi i klientit qĂ« interakton me bazĂ«n e tĂ« dhĂ«nave duhet tĂ« veprojĂ« duke u bazuar nĂ« modelin e bazĂ«s sĂ« tĂ« dhĂ«nave, nĂ« mĂ«nyrĂ« qĂ« nĂ« vetvete tĂ« mos riprodhohet modeli i bazĂ«s sĂ« tĂ« dhĂ«nave si njĂ« âklasĂ« e parĂ«â. Kjo logjikĂ« zakonisht vendoset nĂ« nivelin e qasjes sĂ« tĂ« dhĂ«nave tek ju nĂ« klient.
NĂ« arkitekturĂ«n me dy nivele, e cila ende ekziston nĂ« disa vende, njĂ« model i tillĂ« i sistemit mund tĂ« jetĂ« i vetmi i mundshĂ«m. MegjithatĂ«, nĂ« shumicĂ«n e sistemeve, niveli i qasjes sĂ« tĂ« dhĂ«nave mĂ« duket si njĂ« ânĂ«n sistemâ, qĂ« inkapsulon modelin e bazĂ«s sĂ« tĂ« dhĂ«nave.
Përjashtimet
Nga çdo rregull ka përjashtime, dhe unë kam thënë tashmë se qasja me rëndësinë e bazës së të dhënave dhe gjenerimin e kodit burimor ndonjëherë mund të jetë e papërshtatshme. Këtu janë dy përjashtime të tilla (pranoni se do të ketë edhe të tjera):
- Kur skema Ă«shtĂ« e panjohur dhe duhet tĂ« hapet. PĂ«r shembull, ju jeni ofrues i njĂ« instrumenti qĂ« ndihmon pĂ«rdoruesit tĂ« orientohen nĂ« çdo skemĂ«. Uff. KĂ«tu pa gjenerim kode. Por pĂ«rsĂ«ri â baza e tĂ« dhĂ«nave Ă«shtĂ« mbi tĂ« gjitha.
- Kur skema duhet të gjenerohet në fluks për të zgjidhur një detyrë të caktuar. Ky shembull duket si një version paksa i zbukuruar i modelit , domethënë, ju me të vërtetë nuk keni një skemë të qartë të përcaktuar. Në këtë rast, shpesh nuk mund të jeni të sigurt se ju përshtatet një RDBMS.
Përjashtimet për natyrën e tyre janë të veçanta. Në shumicën e rasteve, që lidhen me përdorimin e RDBMS, skema është e njohur paraprakisht, ajo ndodhet brenda RDBMS dhe është burimi i vetëm i "të vërtetës", dhe të gjithë klientët duhet të krijojnë kopje të saj, të derivuara prej saj. Në ide, në këtë rast, duhet të angazhohet një gjenerator kodi.
Burimi: habr.com
