Relationer i

databaser & Laravel

Dagens föreläsning

Genomgång av hur relationer i databaser fungerar tillsammans med en genomgång av alla de vanligaste relationerna. Efter det så går vi igenom hur relationer fungerar i Laravel.

  • Relationer

    • 1-1

    • 1-*, parent-child

    • *-*

    • EAV

  • Relationer i Laravel

Fälttyper

Ni har säkert redan koll men vi tar dem igen!

  • tinyint/mediumint/int/bigint
  • decimal,numeric
  • double,float,real
  • bit
  • char,varchar,binary,varbinary
  • Texttyperna
  • date,time,year,timestamp,datetime
  • enum,set
  • Spatiala datatyper

Int-familjen

De olika typerna är olika stora. Unsigned gör att den börjar från 0 och alltså inte kan ha ett negativt värde.

Enkel datatyp som gör sig bra som index och primary key. Ofta nyckeln (fniss) i databasrelationer.

Decimal & numeric

Lagrar exakta numeriska värden med decimaler.

I MySQL så är decimal och numeric synonymer och fungerar exakt likadant.

Decimal är det ordet som oftast används och kolumntypen används ofta för att lagra tex pengarvärden där det är viktigt att siffran är exakt.

Definition: salary DECIMAL(5,2)

Med ovanstående definition så kan följande värden lagras: -999.99 till 999.99

Double,float,real

Double, float och real är flyttal vilket är decimaltal som inte är exakta. MySQL kommer genomföra avrundning efter eget huvud om ni försöker lagra ett värde som över eller underskrider fältets precision.

Exempel: Om ni definierar en kolumn som FLOAT(7,4) och sedan försöker lagra 999.00009 så kommer detta avrundas till 999.0001.

Använd inte dessa typer om ni måste vara exakta!

Bit

Används för att lagra binär data där fältets längd bestämmer hur många 1:or och 0:or som ni kan lagra.

BIT(1) kan alltså lagra antingen 1 eller 0.

Mycket ovanlig datatyp i moderna applikationer.

char,varchar,binary,varbinary

Skillnaderna mellan char och varchar är hur de lagras och hur långa de kan vara. Char kan vara max 255 tecken och varchar kan vara max 65 535 tecken numera. Varchar används i princip alltid.

Binary och varbinary lagrar text som byte-strängar och är väldigt ovanliga. Byterepresentationerna för olika tecken bestäms av operativsystemets inställningar så olika datorer kan tolka dessa olika.

Använd inte dessa om du inte är väldigt säker på vad du gör!

Texttyperna

Texttyperna används för att lagra stora textmängder som överskrider varchar:s maxstorlek. Blobtyperna används för att lagra bytesträngar (binär data eller filer).

Båda dessa fälttyper kan lagra väldigt mycket data men det är generellt inte en bra idé att lagra stora filer i databasen!

Ni kan också stöta på begränsningar i hur mycket data som MySQL kan skicka om ni förlitar er på dessa datatyper.

Datumtyperna - DT & TS

DATE-typen lagrar enbart datum i formatet YYYY-MM-DD. DATETIMEoch TIMESTAMP lagrar datum med tidsinformation i formatet YYYY-MM-DD HH:MM:SS.

Skillnaden mellan DATETIME OCH TIMESTAMP är att TIMESTAMP alltid lagras i UTC och konverteras till den gällande tidszonen när datan hämtas. DATETIME är ett fast värde där ni själva måste hålla reda på vilken tidszon som ni lagrat i.

Datumtyperna - TIME & YEAR

TIME används för att lagra stora tidsvärden. Formatet är HHH:MM:SS. Tidsspannet är -838:59:59 till 838:59:59.

YEAR lagrar år. Spannet är 1901 till 2155.

ENUM & SET

ENUM och SET lagrar listor av fasta värden som bestäms när kolumnerna skapas.

Som exempel: size ENUM('x-small', 'small', 'medium', 'large', 'x-large') skapar en ENUM-kolumn där de listade värdena är de enda tillåtna.

Dessa kolumntyper kan vara praktiska om ni i förväg vet exakt vad som skall lagras men blir krångliga om ni ångrar er.

Spatiala datatyper

Används för att lagra spatial information och bygger på OpenGIS-modellen. Dessa typer är väldigt ovanliga och spatial data (tex latitud och longitud) brukar lagras som numeriska värden.

Index

Ett index kan liknas vid en innehållsförteckning för en kolumn. Index används för att snabbt kunna hitta data när ni gör sökningar. Om ett index inte finns på en kolumn så måste MySQL gå igenom alla rader för att hitta värdena.

Index snabbar även upp JOIN, GROUP BY och MIN/MAX men bara om ni använder indexkolumnen!

OBS att index har en kostnad för INSERT och UPDATE eftersom indexet måste uppdateras samtidigt.

Relationer

Precis som i verkliga livet så blir era applikationer tråkiga om de inte har några relationer!

Relationer definieras i er databas genom att skapa kolumner i olika tabeller som hänvisar till varandra.

Det allra vanligaste är att numeriska kolumner (int) används som relationskolumner och de relaterade kolumnerna bör vara index.

Ni kan även använda främmande nycklar för att garantera dataintegritet på databasnivå.

One to One 1-1

Den enklaste relationen rent konceptuellt men lite krångligare att definiera/hålla reda på jämfört med 1-*.

För att skapa en 1-1 så måste ni först ha två tabeller. Ni bestämmer vilken som är huvudtabell och lägger sedan till en kolumn i er sekundärtabell som skall hänvisa till id-kolumnen i huvudtabellen.

För att försäkra er om att relationen verkligen blir 1-1 så måste ni antingen sätta ett unikt index på kolumnen eller hålla reda på detta i er kod.

Exempel: En svensk medborgare har ett personnummer.

One to Many 1-*

Den vanligaste relationstypen. I detta fall så kan det bara finnas ett exemplar i huvudtabellen medan sekundärtabellen kan innehålla flera rader som pekar till samma rad i huvudtabellen.

Precis som 1-1 så skapas relationen genom att man i sekundärtabellen skapar en kolumn som hänvisar till id-kolumnen i primärtabellen.

Exempel: En klass har flera elever

Parent-child 1-*

Parent-child är en specialvariant av 1-*. I det här fallet så lägger man länkkolumnen i samma tabell som huvudkolumnen. Om vi tex har en id-kolumn i vår tabell så kan vi då lägga till en kolumn som vi döper till parent_id som då kan hänvisa till id-kolumnen i samma tabell.

Används ofta för att bygga hierarkiska strukturer för exempelvis menyer. Magentos kategoriträd är ett annat exempel.

Many to Many

Den mest komplicerade relationen. I detta fall så kan båda sidor av relationen vara kopplade till flera rader i den relaterade tabellen.

För att åstadkomma detta så skapar man en så kallad länktabell som innehåller två kolumner, en för varje nyckel från respektive tabell.

Relationen är jämbördig men kan konfigureras på lite olika sätt genom främmande nycklar.

Exempel: En beställning kan ha en eller flera produkter. En produkt kan vara med på en eller flera beställningar.

EAV - Entity Attribute Value

För när du inte bryr dig om din data!

Skämt åsido så används EAV för situationer då vi inte vet exakt hur datan som skall lagras kommer att se ut.

En av lösningarna på detta är att skapa en eller flera EAV-tabeller för att lagra vår data. EAV-tabeller kopplas till en eller flera huvudtabell enligt följande modell:

EAV - forts...

Varje bokstav i förkortningen representerar en kolumn.

Entity är en referens till entiteten som datan är kopplad till.

Attribute är antingen en referens till en attribut-definition eller en beskrivning av attributet.

Value är värdet för attributet.

Exempel på system som använder EAV: WordPress och Magento. WordPress för posts och users, Magento bla för sina produktattribut.

Relationer i Laravel

https://laravel.com/docs/5.5/eloquent-relationships

Relationerna som ni kan skapa i era databaser har även en motsvarighet i kod. I Laravels fall så sätts relationer upp via Eloquent. OBS att ni inte behöver skapa relationer via foreign keys i databasen men det är best practice.

Relationer definieras i våra modeller genom att lägga till metoder som anropar andra speciella metoder som finns inbyggda i Eloquent.

One to One 1-1

I Laravel så defineras en 1-1 med två olika metoder, nämligen:

<?php
public function phone()
{
    return $this->hasOne('App\Phone');
}

public function user()
{
    return $this->belongsTo('App\User');
}

Koden ovan visar båda sidorna av relationen.

One to One 1-1

Koden ovan gör ett antal antaganden om hur er databas är uppbyggd. Som vi pratat om på en tidigare föreläsning så innehåller Laravel en mängd konventioner runt hur saker och ting antas vara som det överlag är en bra idé att följa.

<?php
public function phone()
{
    // Laravel antar att kolumnen user_id kommer att finnas i phones-tabellen
    return $this->hasOne('App\Phone');
}

public function user()
{
    // Laravel antar att kolumnen id kommer att finnas i users-tabellen
    return $this->belongsTo('App\User');
}

One to Many 1-*

I Laravel så defineras en 1-* med två olika metoder, nämligen:

<?php
public function comments()
{
    // Antar att det finns en post_id-kolumn i comments-tabellen
    return $this->hasMany('App\Comment');
}

public function post()
{
    // Antar att det finns en id-kolumn i posts-tabellen
    return $this->belongsTo('App\Post');
}

Koden ovan visar båda sidorna av relationen.

Many to Many *-*

*-* definieras med samma metod i båda modellerna:

<?php
public function users()
{
    return $this->belongsToMany('App\User');
}

public function roles()
{
    return $this->belongsToMany('App\Role');
}

Koden ovan visar båda sidorna av relationen.

Many to Many *-*

Som vi har gått igenom så kräver en *-* en så kallad pivot-tabell. Laravel gissar namnet på pivot-tabellen utifrån namnet på de två tabeller som ingår i relationen. Om vi tex har tabellerna users och roles så kommer Laravel anta att pivot-tabellen heter role_user. Detta är en sammanslagning av tabellnamnen i singular. Tabellnamnen hamnar alltid i alfabetisk ordning.

Tabellen antas innehålla kolumnerna role_id och user_id. Tabellen kan innehålla fler kolumner om ni behöver lagra data relaterat till relationen.

Relationer i databaser & Laravel

By marcusdalgren

Relationer i databaser & Laravel

  • 332