<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Peter de Croos</title>
    <description>The latest articles on DEV Community by Peter de Croos (@cultofmetatron).</description>
    <link>https://dev.to/cultofmetatron</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F48788%2Fd6f3b224-bcf4-48cb-afb1-d92277950768.jpeg</url>
      <title>DEV Community: Peter de Croos</title>
      <link>https://dev.to/cultofmetatron</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cultofmetatron"/>
    <language>en</language>
    <item>
      <title>Database Modeling With Ecto Part 2 - has many and belongs to Relationships</title>
      <dc:creator>Peter de Croos</dc:creator>
      <pubDate>Mon, 17 May 2021 20:56:31 +0000</pubDate>
      <link>https://dev.to/cultofmetatron/database-modeling-with-ecto-part-2-has-many-and-belongs-to-relationships-bam</link>
      <guid>https://dev.to/cultofmetatron/database-modeling-with-ecto-part-2-has-many-and-belongs-to-relationships-bam</guid>
      <description>&lt;p&gt;Previously, we created the initial phoenix app and created a &lt;code&gt;Teacher&lt;/code&gt; struct and table.&lt;br&gt;
We went over how to perform the basic CRUD operations as well as how to do some basic tests to verify the functionality.&lt;br&gt;
In part 2, we're going to be adding more structs and defining relationships between them.&lt;br&gt;
We'll also go over how to fetch records with their associations.&lt;/p&gt;

&lt;p&gt;If you haven't been following along, you can checkout the code from github and fetch the branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:cultofmetatron/database-modeling-with-ecto-example.git
git checkout part1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  has many and belongs to
&lt;/h2&gt;

&lt;p&gt;We now have a &lt;code&gt;Teacher&lt;/code&gt; ecto schema as an interface to out &lt;code&gt;teachers&lt;/code&gt; table.&lt;br&gt;
Lets implement a class.&lt;br&gt;
A &lt;code&gt;Class&lt;/code&gt; at most belongs to one &lt;code&gt;Teacher&lt;/code&gt;.&lt;br&gt;
The standard way to setup a relationship is through foreign keys.&lt;br&gt;
That is a column that matches the a column on another table which msut be unique on the other table.&lt;br&gt;
The type of the foreign key column must match the type of the key on the foreign table that its referencing.&lt;/p&gt;

&lt;p&gt;We will create a column &lt;code&gt;teacher_id&lt;/code&gt; on the &lt;code&gt;classes&lt;/code&gt; table will have a &lt;em&gt;foreign key constraint&lt;/em&gt; on the &lt;code&gt;id&lt;/code&gt; columnn of the &lt;code&gt;teachers&lt;/code&gt; table.&lt;br&gt;
Since the &lt;code&gt;id&lt;/code&gt; column of &lt;code&gt;teachers&lt;/code&gt; is a uuid, the column here will also be a &lt;code&gt;uuid&lt;/code&gt;.&lt;br&gt;
Being the primary key of the table, it alrady satisfies the aformentioned uniqueness contraint.&lt;br&gt;
In ecto, we call it a &lt;code&gt;:binary_id&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;mix phx.gen.schema Class classes name:string teacher_id:references:teachers subject:string active:boolean
&lt;span class="k"&gt;*&lt;/span&gt; creating lib/grade_tracker/class.ex
&lt;span class="k"&gt;*&lt;/span&gt; creating priv/repo/migrations/20210515195753_create_classes.exs

Remember to update your repository by running migrations:

    &lt;span class="nv"&gt;$ &lt;/span&gt;mix ecto.migrate

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we've created the associated class and migrations, we need to make some small adjustments.&lt;/p&gt;

&lt;p&gt;First lets look at the migration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Migrations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CreateClasses&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;primary_key:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;primary_key:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:teacher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:teachers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;on_delete:&lt;/span&gt; &lt;span class="ss"&gt;:nothing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:teacher_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same as teacher, we have an id set with &lt;code&gt;:binary_id&lt;/code&gt; which coresponds to the &lt;code&gt;UUID&lt;/code&gt; type in postgres.&lt;br&gt;
note, that part for teacher id, we have an &lt;code&gt;on_delete: :nothing&lt;/code&gt;.&lt;br&gt;
Change that to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;
&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:teacher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:teachers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;on_delete:&lt;/span&gt; &lt;span class="ss"&gt;:nilify_all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The call to &lt;a href="https://hexdocs.pm/ecto_sql/Ecto.Migration.html#references/2"&gt;&lt;em&gt;references/2&lt;/em&gt;&lt;/a&gt; creates the foreign key constraint.&lt;br&gt;
What this means is any non null values for the teacher_id column of this table &lt;strong&gt;MUST&lt;/strong&gt; corespond to a a record in the &lt;code&gt;teachers&lt;/code&gt; table in the referenced column.&lt;br&gt;
This leads to some edge cases that must be accounted for.&lt;br&gt;
What happens if the referenced teacher record is deleted?&lt;br&gt;
All classes referring to that eacher would have value for &lt;code&gt;teacher_id&lt;/code&gt; that violates the contraint.&lt;br&gt;
If you have a a few classes that belong to this teacher and you try to remove the teacher, you will get an error from the database.&lt;br&gt;
This is rarely what I want.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;on_delete&lt;/code&gt; specifies the action to take place if the referenced record is deleted.&lt;br&gt;
If we leave the value as &lt;code&gt;:nothing&lt;/code&gt;, we will get the error I mentioned.&lt;br&gt;
In this case, I am switching it to &lt;code&gt;:nilify_all&lt;/code&gt;.&lt;br&gt;
This makes the class without a teacher.&lt;br&gt;
In a real world scneario, I could make a dashbaord showing the orphned classes prompting them to assign a teacher.&lt;br&gt;
Alternativly, I could set &lt;code&gt;delete_all&lt;/code&gt; which would remove the classes that reference the teacher.&lt;br&gt;
What you pick for your relationships depend entirely on your use case.&lt;/p&gt;

&lt;p&gt;By default, the key is set to &lt;code&gt;id&lt;/code&gt;. you can overide that by passing in &lt;code&gt;:column&lt;/code&gt;.&lt;br&gt;
We can also add it to make the associated column more explicit.&lt;/p&gt;

&lt;p&gt;If We wanted to make it so that all classes MUST have a teacher id passed in, you could pass &lt;code&gt;null: false&lt;/code&gt; to the column creation.&lt;br&gt;
If you do that, &lt;code&gt;nilify_all&lt;/code&gt; will not work as it will violate the null column contraint.&lt;br&gt;
You will have to either &lt;code&gt;delete_all&lt;/code&gt; or have your app force the user to reasign the class before removing a teacher.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# does the same thing as above&lt;/span&gt;
&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:teacher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:teachers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;on_delete:&lt;/span&gt; &lt;span class="ss"&gt;:nilify_all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;column:&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One more thing, we should make that default for the &lt;code&gt;active&lt;/code&gt; column to be true.&lt;/p&gt;

&lt;p&gt;your migration should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Migrations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CreateClasses&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;primary_key:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;primary_key:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:teacher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:teachers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;on_delete:&lt;/span&gt; &lt;span class="ss"&gt;:delete_all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:teacher_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now lets take a look at the schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Class&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Changeset&lt;/span&gt;

  &lt;span class="nv"&gt;@primary_key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;autogenerate:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;@foreign_key_type&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;
  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"classes"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:teacher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;

    &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;class&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validate_required&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the schema specifies no relationship to Teacher.&lt;br&gt;
We need to modify this schema by replaceing the &lt;code&gt;teacher_id&lt;/code&gt; field with &lt;a href="https://hexdocs.pm/ecto/Ecto.Schema.html#belongs_to/3"&gt;&lt;em&gt;belongs_to/3&lt;/em&gt;&lt;/a&gt;.&lt;br&gt;
it'll probably be a good idea to add a foreing constraint to the validation code in teh changeset as well.&lt;br&gt;
Additionally, we'll remove active as a required field since we have a default and add the &lt;code&gt;:teacher_id&lt;/code&gt; as a castable attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Class&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Changeset&lt;/span&gt;

  &lt;span class="nv"&gt;@primary_key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;autogenerate:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;@foreign_key_type&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;
  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"classes"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;


    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:teacher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Teacher&lt;/span&gt;

    &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;class&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:teacher_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validate_required&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:subject&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;foreign_key_constraint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:teacher_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will note that adding &lt;code&gt;:teacher_id&lt;/code&gt; is optional and may not be appropriate for your use case.&lt;br&gt;
the Belongs to adds other operations we will use to link classes to their associated teachers.&lt;br&gt;
By adding the column directly, you allow the column to be set directly.&lt;br&gt;
This means you should do due diligence when directly passing along user input;&lt;br&gt;
For instance, you take params input from a web request and pass it directly in when creating a changeset.&lt;/p&gt;

&lt;p&gt;Now we we add a &lt;a href="https://hexdocs.pm/ecto/Ecto.Schema.html#has_many/3"&gt;&lt;em&gt;has_many/3&lt;/em&gt;&lt;/a&gt; to the Teacher.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Teacher&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Changeset&lt;/span&gt;

  &lt;span class="nv"&gt;@primary_key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;autogenerate:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;@foreign_key_type&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;
  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"teachers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;

    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Class&lt;/span&gt;

    &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;teacher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;teacher&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validate_required&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have everythign setup in code, lets run the migrations.&lt;br&gt;
Make sure you have the proper configuration setup in &lt;code&gt;config/dev.exs&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;mix ecto.migrate                                                                               &lt;span class="o"&gt;[&lt;/span&gt;2.7.1]

20:34:53.870 &lt;span class="o"&gt;[&lt;/span&gt;info]  &lt;span class="o"&gt;==&lt;/span&gt; Running 20210422234100 GradeTracker.Repo.Migrations.CreateTeachers.change/0 forward
20:34:53.872 &lt;span class="o"&gt;[&lt;/span&gt;info]  create table teachers
20:34:53.876 &lt;span class="o"&gt;[&lt;/span&gt;info]  &lt;span class="o"&gt;==&lt;/span&gt; Migrated 20210422234100 &lt;span class="k"&gt;in &lt;/span&gt;0.0s
20:34:53.893 &lt;span class="o"&gt;[&lt;/span&gt;info]  &lt;span class="o"&gt;==&lt;/span&gt; Running 20210515195753 GradeTracker.Repo.Migrations.CreateClasses.change/0 forward
20:34:53.893 &lt;span class="o"&gt;[&lt;/span&gt;info]  create table classes
20:34:53.898 &lt;span class="o"&gt;[&lt;/span&gt;info]  create index classes_teacher_id_index
20:34:53.899 &lt;span class="o"&gt;[&lt;/span&gt;info]  &lt;span class="o"&gt;==&lt;/span&gt; Migrated 20210515195753 &lt;span class="k"&gt;in &lt;/span&gt;0.0s

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Building Relations
&lt;/h3&gt;

&lt;p&gt;Now that we have a has_many relationship setup between `Teacher, we can start thinking about inserting classes.&lt;/p&gt;

&lt;p&gt;First lets create a new test file &lt;code&gt;/test/grade_tracker_web/schemas/class_test.exs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Since we are testing out connected associations, I've added a setup case that creates a &lt;code&gt;Teacher&lt;/code&gt; struct that we can use for all our demonstrations&lt;/p&gt;

&lt;p&gt;In our schema, a &lt;code&gt;Class&lt;/code&gt; can be produced without a teacher so we can insert one in exactly the same as we could with &lt;code&gt;Teacher&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;&lt;/code&gt;`elixir&lt;br&gt;
defmodule GradeTracker.ClassSchemaTest do&lt;br&gt;
  use  GradeTracker.DataCase&lt;br&gt;
  alias GradeTracker.Repo&lt;br&gt;
  alias GradeTracker.Teacher&lt;br&gt;
  alias GradeTracker.Class&lt;/p&gt;

&lt;p&gt;def create_teacher(context) do&lt;br&gt;
    teacher = %Teacher{}&lt;br&gt;
    |&amp;gt; Teacher.changeset(%{&lt;br&gt;
      name: "Jose Valim"&lt;br&gt;
    })&lt;br&gt;
    |&amp;gt; Repo.insert!()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{:ok, %{ teacher: teacher }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;end&lt;/p&gt;

&lt;p&gt;setup :create_teacher&lt;/p&gt;

&lt;p&gt;test "we can insert a class", %{ teacher: _teacher } do&lt;br&gt;
    assert {:ok, _} = %Class{}&lt;br&gt;
    |&amp;gt; Class.changeset(%{&lt;br&gt;
      name: "botony 101",&lt;br&gt;
      subject: "biology",&lt;br&gt;
    })&lt;br&gt;
    |&amp;gt; Repo.insert()&lt;/p&gt;

&lt;p&gt;end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Since we added &lt;code&gt;:teacher_id&lt;/code&gt; to the list of castable attributes, we can pass it in directly.&lt;br&gt;
Once its set, we can load the associated item into the structure using &lt;a href="https://hexdocs.pm/ecto/Ecto.Repo.html#c:preload/3"&gt;Repo.preload/3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`elixir&lt;br&gt;
defmodule GradeTracker.ClassSchemaTest do&lt;br&gt;
    #...&lt;/p&gt;

&lt;p&gt;test "we can insert a teacher with a class by setting the column directly",  %{ teacher: teacher } do&lt;br&gt;
    assert {:ok, class} = %Class{}&lt;br&gt;
    |&amp;gt; Class.changeset(%{&lt;br&gt;
      name: "botony 101",&lt;br&gt;
      subject: "biology",&lt;br&gt;
      teacher_id: teacher.id&lt;br&gt;
    })&lt;br&gt;
    |&amp;gt; Repo.insert()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assert class.teacher_id == teacher.id
class = class |&amp;gt; Repo.preload([:teacher])

assert %Teacher{ name: "Jose Valim", id: teacher_id } = class.teacher
assert teacher_id == teacher.id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;end&lt;/p&gt;

&lt;p&gt;end&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Ecto.build_assoc
&lt;/h4&gt;

&lt;p&gt;Setting up a &lt;code&gt;has_many&lt;/code&gt; in the schema provides a lot of information to Ecto for how to link up associated database structs.&lt;br&gt;
The example above only works if you are directly casting a teacher_id.&lt;br&gt;
In practice, you are more likely to use Ecto's &lt;a href="https://hexdocs.pm/ecto/Ecto.html#build_assoc/3"&gt;Ecto.build_assoc/3&lt;/a&gt; to create a new struct based on has_many relationships. You can pass this into your changeset function to create changesets with the association set.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`elixir&lt;br&gt;
defmodule GradeTracker.ClassSchemaTest do&lt;br&gt;
    #...&lt;/p&gt;

&lt;p&gt;test "we can insert a teacher with a class with build_assoc",  %{ teacher: teacher } do&lt;br&gt;
    assert {:ok, class} = teacher&lt;br&gt;
    |&amp;gt; Ecto.build_assoc(:classes) # we get it from the key you set in the schmema after has_many&lt;br&gt;
    |&amp;gt; Class.changeset(%{&lt;br&gt;
      name: "botony 101",&lt;br&gt;
      subject: "biology"&lt;br&gt;
    })&lt;br&gt;
    |&amp;gt; Repo.insert()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assert class.teacher_id == teacher.id
class = class |&amp;gt; Repo.preload([:teacher])

assert %Teacher{ name: "Jose Valim", id: teacher_id } = class.teacher
assert teacher_id == teacher.id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;end&lt;/p&gt;

&lt;p&gt;end&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Ecto.Changeset.put_assoc
&lt;/h4&gt;

&lt;p&gt;We can also build a &lt;code&gt;Teacher&lt;/code&gt; from a &lt;code&gt;Class&lt;/code&gt; but they wont be connnected with an association.&lt;/p&gt;

&lt;p&gt;This is because we aren't writing anything to the class which is where the column that sets the association is set.&lt;br&gt;
We would have to set that explicitly using &lt;a href="https://hexdocs.pm/ecto/Ecto.Changeset.html#put_assoc/4"&gt;Ecto.Changeset.put_assoc/4&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: you will need to preload the association before you attempt to upadate the association.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`elixir&lt;/p&gt;

&lt;p&gt;defmodule GradeTracker.ClassSchemaTest do&lt;br&gt;
   #...&lt;/p&gt;

&lt;p&gt;test "we build a teacher from a class using build assoc as well",  %{ teacher: _teacher } do&lt;br&gt;
    assert {:ok, class} = %Class{}&lt;br&gt;
    |&amp;gt; Class.changeset(%{&lt;br&gt;
      name: "botony 101",&lt;br&gt;
      subject: "biology",&lt;br&gt;
    })&lt;br&gt;
    |&amp;gt; Repo.insert()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assert {:ok, teacher } = class
|&amp;gt; Ecto.build_assoc(:teacher)
|&amp;gt; Teacher.changeset(%{
  name: "Richard Feynman"
})
|&amp;gt; Repo.insert()

# the association has to be loaded before we can alter it, leave this oput and you'll get an error
class = class |&amp;gt; Repo.preload([:teacher])

assert {:ok, class} = class
  |&amp;gt; Class.changeset(%{})
  |&amp;gt; Ecto.Changeset.put_assoc(:teacher, teacher)
  |&amp;gt; Repo.update()

class = class |&amp;gt; Repo.preload([:teacher], force: true) #we force a refresh to get the new data

assert class.teacher_id == teacher.id


assert %Teacher{ name: "Richard Feynman", id: teacher_id } = class.teacher
assert teacher_id == teacher.id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;end&lt;/p&gt;

&lt;p&gt;end&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And With that, you have the tools to construct relations based on has_many and belongs_to.&lt;br&gt;
to wrap things up.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key ideas
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;A refernces id is used to set a record as belonging to another record.&lt;/li&gt;
&lt;li&gt;You can use &lt;strong&gt;build_assoc&lt;/strong&gt; to create an associated record for insertion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;put_assoc&lt;/strong&gt; is used to set an association after the fact.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next I'll go over how to create many to many relationships.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>sql</category>
      <category>posgresql</category>
    </item>
    <item>
      <title>Database Modeling with Ecto: Part 1</title>
      <dc:creator>Peter de Croos</dc:creator>
      <pubDate>Mon, 17 May 2021 20:52:50 +0000</pubDate>
      <link>https://dev.to/cultofmetatron/database-modeling-with-ecto-part-1-376h</link>
      <guid>https://dev.to/cultofmetatron/database-modeling-with-ecto-part-1-376h</guid>
      <description>&lt;h2&gt;
  
  
  Creating your first records
&lt;/h2&gt;

&lt;h1&gt;
  
  
  Contents
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Relational modelling in Ecto&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ecto Schema Fundamentals&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Relational modelling in Ecto
&lt;/h1&gt;

&lt;p&gt;You've heard of elixir and are just getting started with your first taste of the kool-aid.&lt;/p&gt;

&lt;p&gt;If you're new to Elixir, you're probably finding ecto to be a bit of a culture shock.&lt;br&gt;
Ecto is an immensly powerful library for working with sql but Unlike other ORMs you may have used, Ecto embraces what makes sql great.&lt;br&gt;
ORMs like active record or django's python objects try to hide sql behind their language specifc interfaces.&lt;br&gt;
SQL Land however, does not deal with objects.&lt;br&gt;
Ecto takes SQL as it is an gives you very powerful tools for modeling yoru application's database layer without building abstractions that ultimatly hinder you later on with slow queries and magic behavior that gets in your way.&lt;/p&gt;

&lt;p&gt;Of course, this means you need to know how to think in sql and the relational model.&lt;/p&gt;
&lt;h3&gt;
  
  
  Thinking in Relationships
&lt;/h3&gt;

&lt;p&gt;I'll spare you the theoratical gibber jabber about industry jargon like "third normal form" and "denormalization".&lt;br&gt;
Frankly, a lot of books on sql modeling get high on the theoretical horse to cover every single possible edge case imaginable.&lt;br&gt;
As somone who learned sql on the job, I've distilled it down to a a few rules of thumb with the occasional exception.&lt;/p&gt;

&lt;p&gt;The secret to thinking in sql is right here in the word "relational."  Almost all relations you will model fit one of three catagroies.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;has many&lt;/code&gt; B&lt;/li&gt;
&lt;li&gt;B &lt;code&gt;belongs to&lt;/code&gt; A&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;has many&lt;/code&gt; C and B &lt;code&gt;has many&lt;/code&gt; C&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;has many&lt;/code&gt; B &lt;code&gt;through&lt;/code&gt; C (if B also &lt;code&gt;has_many&lt;/code&gt; A &lt;code&gt;through&lt;/code&gt; C, we might call this a &lt;code&gt;many to many&lt;/code&gt; relationship)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Any nontrivial database schema is goign to have all of these relationships modeled in one way or another.&lt;br&gt;
To make this all a bit more relatable, lets plan a schema for a school grade tracker.&lt;br&gt;
This could very well be the heart of a system that helps etachers quickly grade their students and send out report cards.&lt;/p&gt;

&lt;p&gt;Cosnider the following relationships.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;Class&lt;/code&gt; has one &lt;code&gt;Teacher&lt;/code&gt;: &lt;code&gt;belongs to&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Student&lt;/code&gt; attends many &lt;code&gt;Class&lt;/code&gt;: &lt;code&gt;has many&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Class&lt;/code&gt; has many &lt;code&gt;Student&lt;/code&gt;: &lt;code&gt;has many&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Class&lt;/code&gt; has many &lt;code&gt;Student&lt;/code&gt; and only one &lt;code&gt;Teacher&lt;/code&gt;:  &lt;code&gt;many to many&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Right here we have a few relationships mapped out.&lt;br&gt;
Given the following the information, we can also infer some secondary effect&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;Student&lt;/code&gt; has many &lt;code&gt;Teacher&lt;/code&gt; &lt;code&gt;through&lt;/code&gt; a &lt;code&gt;Class&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;Teacher&lt;/code&gt; has many &lt;code&gt;Student&lt;/code&gt; &lt;code&gt;through&lt;/code&gt; a &lt;code&gt;Class&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We still havent gotten to grades! But where to store it?&lt;br&gt;
Thinking about grades, I would model it as an operation over a group of &lt;code&gt;Assignment&lt;/code&gt;.&lt;br&gt;
It makes sense to think about it in terms of the &lt;code&gt;Enrollment&lt;/code&gt; of the students.&lt;/p&gt;

&lt;p&gt;With that we can add a few more relationships and associated constrants&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;Enrollment&lt;/code&gt; &lt;code&gt;joins&lt;/code&gt; a &lt;code&gt;Student&lt;/code&gt; and &lt;code&gt;Class&lt;/code&gt; to establish a &lt;code&gt;many to many&lt;/code&gt; relationship&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;Enrollment&lt;/code&gt; &lt;code&gt;has many&lt;/code&gt; &lt;code&gt;Assignment&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have a birds eye map of the schema we want to build and model, we can start to hash out the details in code!&lt;/p&gt;
&lt;h3&gt;
  
  
  Ecto Schema Fundamentals
&lt;/h3&gt;

&lt;p&gt;First, install the phoenix generator and run the following to create your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix phx.new &lt;span class="nt"&gt;--binary-id&lt;/span&gt; &lt;span class="nt"&gt;--database&lt;/span&gt; postgres grade_tracker 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every record in yoru database needs a &lt;code&gt;primary key&lt;/code&gt;.&lt;br&gt;
This is a column thatserves as a unique key for a particular record in a table.&lt;br&gt;
By default, phoenix sets up autoincrementing integers as the primary keys.&lt;br&gt;
Setting the &lt;code&gt;--binary-id&lt;/code&gt; flag ensures we'll be generating uuid primary keys &lt;br&gt;
You are more than welcome to use the default autoincrement integers instead. &lt;br&gt;
They are faster and arguably easier to index.&lt;br&gt;
However, uuids are harder to blindly guess and will be useful if later you decide to spread your data out to multiple systems.&lt;/p&gt;

&lt;p&gt;We need a teachers table and schema so lets fire up the generator&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;mix phx.gen.schema Teacher teachers name:string
&lt;span class="k"&gt;*&lt;/span&gt; creating lib/grade_tracker/teacher.ex
&lt;span class="k"&gt;*&lt;/span&gt; creating priv/repo/migrations/20210414205427_create_teachers.exs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a migration that creates out  &lt;code&gt;teachers&lt;/code&gt; table and a schema file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# priv/repo/migrations/20210414205427_create_teachers.exs&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Migrations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CreateTeachers&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:teachers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;primary_key:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;primary_key:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;

      &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, we get 4 colums created. &lt;code&gt;id&lt;/code&gt; is set as the primary key, and &lt;code&gt;name&lt;/code&gt; completes the list of ones we created.&lt;br&gt;
&lt;code&gt;timestamps()&lt;/code&gt; adds &lt;code&gt;inserted_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; columns.&lt;/p&gt;

&lt;p&gt;The schema that was generated is the interface for how we will interact with this table&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Teacher&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Changeset&lt;/span&gt;

  &lt;span class="nv"&gt;@primary_key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;autogenerate:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;@foreign_key_type&lt;/span&gt; &lt;span class="ss"&gt;:binary_id&lt;/span&gt;
  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"teachers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;

    &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;teacher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;teacher&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# pulls the name attribute into the changeset&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validate_required&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# validates that a name attribute exists either on the teacher or the attrs&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of objects, Elixir gives us &lt;a href="https://elixircasts.io/intro-to-structs"&gt;structs&lt;/a&gt;.&lt;br&gt;
The distinction is that there are no instance methods or mutable state.&lt;br&gt;
It represents the state of the record as it was retrieved from the backend.&lt;br&gt;
A struct is a datastructure similar to &lt;a href="https://hexdocs.pm/elixir/1.0.5/Map.html"&gt;Map&lt;/a&gt; with a difference that the keys are defined up front.&lt;/p&gt;

&lt;p&gt;In this module, &lt;code&gt;use Ecto.Schema&lt;/code&gt; meanst that the &lt;code&gt;Teacher&lt;/code&gt; module inherits the behavior of the an Ecto Schema.&lt;br&gt;
It does this through a macro system which is beyond the cope of this article but worth deliving into.&lt;/p&gt;

&lt;p&gt;As you can see, there is one function defined.&lt;br&gt;
The &lt;code&gt;changeset/2&lt;/code&gt; function takes a schema struct and a set of params.&lt;br&gt;
It returns an Ecto.Changeset record that carries with it information pertaining to a database change oepration.&lt;br&gt;
Ecto expects that you may have different operations with different validation rules depending on the context of the operation and its perfectly fine to have different functions for generating different types of changesets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For a complete list of built in validations, &lt;a href="https://hexdocs.pm/ecto/Ecto.Changeset.html"&gt;checkout the docs for Ecto.Changeset&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Inserting records
&lt;/h3&gt;

&lt;p&gt;Database Operations are done via &lt;code&gt;Repo&lt;/code&gt; aliased from &lt;code&gt;GradeTracker.Repo&lt;/code&gt;. Its a microservice that you pass data to and get back the result of your operations.&lt;br&gt;
To insert a record, we create a &lt;code&gt;Teacher&lt;/code&gt; changeset.&lt;br&gt;
Since we are creating a new one, we can pass in a new Teacher struct alogn with some paramaters.&lt;/p&gt;

&lt;p&gt;Lets test out our new teacher schema. Create a file &lt;code&gt;test/schemas/teacher_test.exs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TeacherSchemaTest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt;  &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;DataCase&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Repo&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Teacher&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"we can insert a teacher"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Teacher&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Jose Valim"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_teacher&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Teacher&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Teacher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
      &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Jose Valim"&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon a successsful insertion, the insert operation, returns &lt;code&gt;{:ok, *struct* }&lt;/code&gt;.&lt;br&gt;
The struct returned represents the state of that record in the database.&lt;br&gt;
Not only does it have a name attribute, it also has an id which was generated during the insertion.&lt;/p&gt;

&lt;p&gt;now lets run this test!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;mix &lt;span class="nb"&gt;test&lt;/span&gt;
....

Finished &lt;span class="k"&gt;in &lt;/span&gt;0.1 seconds
4 tests, 0 failures

Randomized with seed 80769
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For completeness sake, lets verify that an error gets returned if we leave off the &lt;code&gt;:name&lt;/code&gt; attr.&lt;br&gt;
If &lt;code&gt;Repo.insert/1&lt;/code&gt; errors, we get back an error tuple giving us a changeset with the errors embedded within.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TeacherSchemaTest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;#...&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"inserting a teacher errors without a name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Changeset&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;errors:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"can't be blank"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;validation:&lt;/span&gt; &lt;span class="ss"&gt;:required&lt;/span&gt;&lt;span class="p"&gt;]}],&lt;/span&gt;
      &lt;span class="ss"&gt;valid?:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_changeset&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Teacher&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Teacher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;(%{})&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Updating records
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Repo.update/1&lt;/code&gt; accepts a changeset and operates similarly to &lt;code&gt;Repo.insert/1&lt;/code&gt; with the exception that a primary key must exist on the struct passed into the chanegset creation.&lt;br&gt;
If you try to update a record without a primary key, you will raise an exception rather than get an error tuple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GradeTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TeacherSchemaTest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;#...&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"updating a teacher errors without an id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;assert_raise&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;NoPrimaryKeyValueError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Teacher&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Teacher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Dave Thomas"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deleting a record
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Repo.delete/1&lt;/code&gt; accepts a struct and deletes it. You'll get back &lt;code&gt;{:ok, teacher}&lt;/code&gt; that returns the deleted record&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"deleting a teacher"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;teacher&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Teacher&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Teacher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
      &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Jose Valim"&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;teacher&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;teacher&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that, you can now create, update and delete a single record. In my followup, I'll cover how to setup relations and transactions&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>database</category>
      <category>posgresql</category>
    </item>
  </channel>
</rss>
