Constraints
Constraints är säkerhetsbältena i databasen – de hindrar felaktig data från att ens komma in. När du lär dig använda dem rätt slipper du skriva massor av extra kod för att sanera data i efterhand.
TL;DR
PRIMARY KEYochFOREIGN KEYhåller ordning på identitet och relationer.NOT NULL,UNIQUE,CHECKochDEFAULTser till att kolumner beter sig som du tänkt.- Kombinera constraints med index och transaktioner för robusta system.
Översikt
| Constraint | Vad den gör | Typiskt exempel |
|---|---|---|
PRIMARY KEY | Unikt, icke-null, identifierar en rad | Id INTEGER PRIMARY KEY |
FOREIGN KEY | Peker på primärnyckel i annan tabell | AuthorId REFERENCES Authors(AuthorId) |
NOT NULL | Tvingar fram värde | Name TEXT NOT NULL |
UNIQUE | Tillåter värde bara en gång | Email TEXT UNIQUE |
CHECK | Eget villkor per rad | CHECK (Stock >= 0) |
DEFAULT | Förifyllt värde när INSERT saknar kolumn | CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP |
Exempel: komplett tabell
CREATE TABLE Orders (
OrderId INTEGER PRIMARY KEY,
CustomerId INTEGER NOT NULL,
OrderDate DATE NOT NULL DEFAULT CURRENT_DATE,
TotalAmount DECIMAL(12,2) CHECK (TotalAmount >= 0),
Status TEXT NOT NULL CHECK (Status IN ('Draft','Sent','Paid','Cancelled')),
UNIQUE (CustomerId, OrderDate),
FOREIGN KEY (CustomerId)
REFERENCES Customers(CustomerId)
ON UPDATE CASCADE
ON DELETE RESTRICT
);
Primärnycklar
- Ska vara korta och stabila: använd
INTEGER/BIGINTellerGUID(om distribuerat system). - I SQLite/SQL Server kan du använda
INTEGER PRIMARY KEY+AUTOINCREMENT/IDENTITY. - Undvik att låta affärsdata (t.ex. personnummer) vara primärnyckel – de kan behöva ändras.
Främmande nycklar
- Definiera alltid
ON DELETE/ON UPDATE-beteenden så att framtiden inte blir överraskning.CASCADEnär barn ska tas bort automatiskt.RESTRICTellerNO ACTIONnär du vill stoppa borttagning.SET NULLnär relationen är frivillig.
- Indexera kolumen som refererar – annars blir JOINs tröga.
Datakvalitet med NOT NULL, UNIQUE och CHECK
ALTER TABLE Products
ADD CONSTRAINT CK_Products_Price CHECK (Price >= 0);
ALTER TABLE Products
ADD CONSTRAINT UQ_Products_Sku UNIQUE (Sku);
CHECK kan kombinera flera kolumner:
CHECK (SalePrice <= RegularPrice OR SalePrice IS NULL)
DEFAULT – smarta startvärden
- Bra för tidsstämplar (
DEFAULT CURRENT_TIMESTAMP). - Används ofta tillsammans med
BIT/BOOLEANflaggor, t.ex.IsActive BIT DEFAULT 1. - Kom ihåg att DEFAULT inte körs när du explicit skickar
NULL– kombinera medNOT NULLom värdet är obligatoriskt.
Checklista innan du deployar schemat
- Har varje tabell en primärnyckel?
- Är alla obligatoriska kolumner markerade som
NOT NULL? - Har varje relation en tydlig
ON DELETE/UPDATE-regel? - Finns unika constraints där du kräver unika värden (t.ex. e-post)?
- Finns det
CHECK-villkor på kritiska siffror som inte får vara negativa?
Vanliga misstag
- Glömda index på foreign keys → långsamma JOINs.
- Överlappande constraints (t.ex. både UNIQUE och
PRIMARY KEYpå samma kolumn utan anledning). - Fel ordning vid dataimport – skapa constraints efter att du laddat legacy-data, sedan aktivera dem.
- Silent fail: i SQLite måste
PRAGMA foreign_keys = ON;aktiveras i varje connection, annars ignoreras constraints.
Koppling till C#
| SQL constraint | Motsvarighet i C# / EF Core |
|---|---|
PRIMARY KEY | [Key] eller modelBuilder.Entity().HasKey() |
FOREIGN KEY | Navigation properties + HasOne/WithMany |
NOT NULL | Required i data annotations/fluently |
UNIQUE | HasIndex(...).IsUnique() |
CHECK | HasCheckConstraint() |
DEFAULT | HasDefaultValue() eller HasDefaultValueSql() |
Sammanfattning
- Constraints är första försvarslinjen – låt databasen hjälpa dig hålla datan ren.
- Kombinera flera constraint-typer för att uttrycka affärsregler direkt i schemat.
- Dokumentera alltid varför du valt en viss
ON DELETE-strategi så att framtida utvecklare vet vad som gäller.
Dad joke
Varför älskar databasen regler? För att då blir det inte så många relationsproblem.