Elixir og Phoenix: Skalerbar backendutvikling · leksjon

Assosiasjoner og innebygde skjemaer

Håndter relasjoner mellom ulike datamodeller ved hjelp av Ecto-assosiasjoner, og bygg inn data direkte med innebygde skjemaer.

Leksjon 3 av 411 trinn

Assosiasjoner og innebygde skjemaer er en gratis leksjon i Elixir og Phoenix: Skalerbar backendutvikling på CoddyKit. Dette er leksjon 3 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Elixir og Phoenix: Skalerbar backendutvikling, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Elixir og Phoenix: Skalerbar backendutvikling inneholder totalt 4 leksjoner.

Knytte dataene sammen

I relasjonsdatabaser er data ofte fordelt på flere tabeller for å unngå redundans og sikre dataintegritet. Assosiasjoner i Ecto hjelper Dem med å definere hvordan disse ulike delene av data henger sammen.

Tenk på en blogg: En bruker kan skrive mange innlegg, og hvert innlegg tilhører én bruker. Ecto lar Dem modellere disse relasjonene direkte i Elixir-skjemaene.

  • Organiserer relaterte data på en logisk måte.
  • Forenkler spørringer og uthenting av data.
  • Opprettholder datakonsistens.

Én bruker, mange innlegg

Den vanligste relasjonen er én-til-mange. For eksempel kan én User ha mange Post-poster, men hver Post tilhører bare én User.

I Ecto definerer De dette ved å bruke has_many på «én»-siden (for eksempel User) og belongs_to på «mange»-siden (for eksempel Post). Makroen belongs_to forteller også Ecto at det skal legges til en fremmednøkkel (for eksempel user_id) i databasetabellen til Post.

Kode med `has_many` og `belongs_to`

La oss definere User- og Post-skjemaene. Legg merke til hvordan has_many og belongs_to knytter dem sammen. Makroen belongs_to forventer navnet på assosiasjonen og modulen til det tilknyttede skjemaet.

defmodule MyApp.User do
  use Ecto.Schema
  schema "users" do
    field :name, :string
    has_many :posts, MyApp.Post # A user has many posts

    timestamps()
  end
end

defmodule MyApp.Post do
  use Ecto.Schema
  schema "posts" do
    field :title, :string
    field :content, :string
    belongs_to :user, MyApp.User # A post belongs to one user

    timestamps()
  end
end

Arbeide med koblede poster

Når skjemaene er definert, kan De opprette poster og knytte dem sammen. Ecto lar Dem forhåndslaste assosiasjoner ved å hente relaterte data i én enkelt spørring, slik at N+1-problemer unngås. Slik kan De opprette en bruker og innlegg og deretter vise brukeren med innleggene sine.

defmodule MyScript do
  # Mock schemas for demonstration (assuming they are defined)
  defmodule User do
    defstruct [:id, :name, :posts]
  end
  defmodule Post do
    defstruct [:id, :title, :content, :user_id]
  end

  def run do
    IO.puts "--- Demonstrating One-to-Many ---"
    # Simulate creating a user
    user = %User{id: 1, name: "Alice"}
    IO.inspect user, label: "Created User"

    # Simulate creating posts linked to the user
    post1 = %Post{id: 101, title: "My First Post", content: "Hello world!", user_id: user.id}
    post2 = %Post{id: 102, title: "Elixir Fun", content: "Learning Elixir!", user_id: user.id}

    # In a real app, you'd use Repo.insert! and Repo.preload
    # To show the concept of preloading, we manually add posts to the user struct
    user_with_posts = %{user | posts: [post1, post2]}

    IO.inspect user_with_posts, label: "User with preloaded posts"
  end
end

MyScript.run()

Flere koblinger: `many_to_many`

Noen ganger har poster en mange-til-mange-relasjon. For eksempel kan en Student melde seg på mange Course-kurs, og hvert Course kan ha mange Student-studenter.

Ecto håndterer dette ved hjelp av en koblingstabell (eller «pivot-tabell»). De definerer et skjema for denne mellomliggende tabellen, og Ecto bruker det til å administrere koblingene mellom de to hovedskjemaene med makroen many_to_many.

  • Krever et separat koblingsskjema.
  • Knytter sammen to skjemaer der begge sider kan ha flere relaterte poster.
  • Vanlig for tagger, roller eller gruppemedlemskap.

Kode med `many_to_many`

La oss definere Student- og Course-skjemaene sammen med et Enrollment-koblingsskjema. Makroen many_to_many brukes på både Student og Course, og koblingsskjemaet angis.

defmodule MyApp.Student do
  use Ecto.Schema
  schema "students" do
    field :name, :string
    many_to_many :courses, MyApp.Course, join_through: MyApp.Enrollment

    timestamps()
  end
end

defmodule MyApp.Course do
  use Ecto.Schema
  schema "courses" do
    field :title, :string
    many_to_many :students, MyApp.Student, join_through: MyApp.Enrollment

    timestamps()
  end
end

defmodule MyApp.Enrollment do
  use Ecto.Schema
  schema "enrollments" do
    # These are foreign keys to Student and Course
    belongs_to :student, MyApp.Student
    belongs_to :course, MyApp.Course

    timestamps()
  end
end

Få tilgang til mange-til-mange-koblinger

På samme måte som ved én-til-mange bruker De Ecto.Repo.preload/2 til å hente tilknyttede mange-til-mange-poster. Ecto håndterer automatisk spørringen mot koblingstabellen i bakgrunnen.

defmodule MyScript.Many do
  # Mock schemas for demonstration
  defmodule Student do
    defstruct [:id, :name, :courses]
  end
  defmodule Course do
    defstruct [:id, :title, :students]
  end
  defmodule Enrollment do
    defstruct [:id, :student_id, :course_id]
  end

  def run do
    IO.puts "--- Demonstrating Many-to-Many ---"
    # Simulate creating a student and courses
    student1 = %Student{id: 1, name: "Maria"}
    courseA = %Course{id: 101, title: "Elixir Basics"}
    courseB = %Course{id: 102, title: "Phoenix Framework"}

    # Simulate enrollments (join table entries)
    _enrollment1 = %Enrollment{student_id: student1.id, course_id: courseA.id}
    _enrollment2 = %Enrollment{student_id: student1.id, course_id: courseB.id}

    # Simulate preloading courses for student1
    student1_with_courses = %{student1 | courses: [courseA, courseB]}

    IO.inspect student1_with_courses, label: "Student with preloaded courses"
  end
end

MyScript.Many.run()

Data i data: Innebygde skjemaer

Mens assosiasjoner kobler sammen separate poster, lar innebygde skjemaer deg lagre strukturerte data direkte i et felt i en overordnet post. Det betyr at de innebygde dataene ikke ligger i en separat tabell, men er en del av raden til den overordnede posten.

Bruk innebygde skjemaer når de nøstede dataene bare gir mening i sammenheng med den overordnede posten, og ikke trenger å spørres etter eller deles separat.

  • Data lagres direkte i den overordnede posten.
  • Ingen separat databasetabell eller fremmednøkler.
  • Ideelt for enkle, avhengige nøstede data som adresser eller metadata.

Koding av innebygde skjemaer

Du definerer et innebygd skjema ved å bruke embeds_one eller embeds_many i det overordnede skjemaet. Selve det innebygde skjemaet bruker Ecto.Schema sammen med @primary_key false og @foreign_key_type :binary_id (eller false hvis det ikke skal ha noen ID), siden det ikke er en frittstående tabell.

defmodule MyScript.Embed do
  defmodule Address do
    use Ecto.Schema
    @primary_key false # Embedded schemas don't have their own primary key
    @foreign_key_type :binary_id # Or false if no ID needed at all
    schema "addresses" do # Table name is ignored for embeds
      field :street, :string
      field :city, :string
      field :zip_code, :string
    end
  end

  defmodule Profile do
    use Ecto.Schema
    schema "profiles" do
      field :username, :string
      embeds_one :address, MyScript.Embed.Address, on_replace: :delete # Embeds one address

      timestamps()
    end
  end

  def run do
    IO.puts "--- Demonstrating Embedded Schemas ---"
    # Create a profile with an embedded address
    profile_changeset =
      Ecto.Changeset.change(%Profile{}, %{username: "john_doe"})
      |> Ecto.Changeset.put_embed(:address, %{
        street: "123 Main St",
        city: "Anytown",
        zip_code: "12345"
      })

    # In a real app: Repo.insert!(profile_changeset)
    # Simulate the resulting struct
    profile_with_address = %Profile{
      id: 1,
      username: "john_doe",
      address: %Address{street: "123 Main St", city: "Anytown", zip_code: "12345"}
    }

    IO.inspect profile_with_address, label: "Profile with embedded address"
  end
end

MyScript.Embed.run()

Test forståelsen

Du har lært om Ecto-assosiasjoner og innebygde skjemaer. La oss teste kunnskapene dine!

Assosiasjoner og innebygde skjemaer: Viktige punkter

Godt jobbet! Du har fått kontroll på hvordan relasjoner modelleres i Ecto:

  • En-til-mange: Bruk has_many og belongs_to. Fremmednøkkelen ligger på belongs_to-siden.
  • Mange-til-mange: Bruk many_to_many sammen med et eget join_through-skjema.
  • Innebygde skjemaer: Bruk embeds_one eller embeds_many til å lagre avhengige, strukturerte data direkte i en overordnet post.
  • Bruk alltid Ecto.Repo.preload/2 for å hente tilknyttede data effektivt.

Disse kraftige funksjonene er grunnleggende for å bygge robuste og velstrukturerte Ecto-applikasjoner. Fortsett å øve!

Gratis å komme i gang

Lær deg Elixir med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
12
Leksjoner
48

Ofte stilte spørsmål

Er leksjonen «Assosiasjoner og innebygde skjemaer» gratis?

Ja – hele teksten i «Assosiasjoner og innebygde skjemaer» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Elixir og Phoenix: Skalerbar backendutvikling-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Elixir og Phoenix: Skalerbar backendutvikling inneholder totalt 4 leksjoner.

Hva lærer jeg i «Assosiasjoner og innebygde skjemaer»?

Håndter relasjoner mellom ulike datamodeller ved hjelp av Ecto-assosiasjoner, og bygg inn data direkte med innebygde skjemaer. Du øver på Elixir og Phoenix: Skalerbar backendutvikling med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Elixir og Phoenix: Skalerbar backendutvikling?

Ingen tidligere erfaring er nødvendig. Elixir og Phoenix: Skalerbar backendutvikling på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Assosiasjoner og innebygde skjemaer»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Elixir og Phoenix: Skalerbar backendutvikling-leksjonen?

Ja. Alle Elixir og Phoenix: Skalerbar backendutvikling-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Ecto-skjemaer og databasemigreringer
  2. Repo, Changesets og spørringer
  3. Assosiasjoner og innebygde skjemaer
  4. Transaksjoner og Ecto.Multi
← Tilbake til Elixir og Phoenix: Skalerbar backendutvikling