Seeding database with relationships

Hi guys… Coming to Elixir from C# has been a great challenge to me since these languages are in completely opposite positions on the spectrum (OOP vs Function, Static vs Dynamic, etc).
So, I was wondering how can I translate what I do today with C# + Entity to Elixir + Ecto:

Considering the following code:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public User Author { get; set; }
}

PS.: As you can see, I don’t need to specify the User foreign key inside Post class directly.

Then, for seeding the database I can just:

var posts = new List<Post>() 
{ 
    new Post { Title: "Elixir good practices"  }, 
    new Post { Title: "Programming in Phoenix"  } 
};
db.Users.Add(new User { Name: "John Doe", Posts = posts  });
db.SaveChanges();

The code above will automatically create and associate those posts to that user.
Besides that, I’m not obligated to deal directly with the FK within a Post, I can access it like: post.Author or optionally add a primitive to access the FK like: post.UserId. How can I do that with Elixir and Ecto?

1 Like

The same style can be used in Ecto with has_many associations.

See chapter 7 of “what’s new in Ecto 2” ebook for some examples: http://blog.plataformatec.com.br/wp-content/uploads/2016/12/whats-new-in-ecto-2-0-1.pdf#page37

@mbuhot Thanks for the reference, I’ve managed to reproduce the behavior putting a user inside a post, but the other way around does not seem to work for me - if I create a user and put posts inside it, the author_id column on the posts table is null:

schema "users" do
    field :name, :string
    has_many :posts, Post
end

schema "posts" do
    field :title, :string
    belongs_to :author, User
end

Then…

# works
Repo.insert! %Post{
    title: "Elixir is awesome!",
    author: %User{name: "John Doe"}
}

# does not work
Repo.insert! %User{
    name: "John Doe",
    posts: [ 
        %Post{title: "Elixir good practices"}, 
        %Post{title: "Programming in Phoenix"} 
    ]
}

The foreign_key option needs to be set on User.posts.

:foreign_key - Sets the foreign key, this should map to a field on the other schema, defaults to the underscored name of the current schema suffixed by _id

schema "users" do
  field :name, :string
  has_many :posts, Post, foreign_key: :author_id

  timestamps()
end

If you force a recompile, you should hopefully see a warning like:

mix compile --force
Compiling 12 files (.ex)
warning: invalid association `posts` in schema Blog.Blog.User: associated schema Blog.Blog.Post does not have field `user_id`
  lib/blog/blog/user.ex:1: Blog.Blog.User (module)
5 Likes

Awesome! Thanks a lot for the explanation…
I was expecting Ecto to have a little more “magic” under the hood like Entity Framework does; for instance, assuming the author_id fk based on the name I gave to the field.

Also, I was not aware that was necessary to mix compile --force; so just mix compile wasn’t showing any warnings. This is really great, thanks! :wink:

2 Likes

Interesting transition, I mean from c# and VS to Phoenix and Elixir. I enjoy coding with both of them. Intersting to hear what you consider as advantages using Phoenix over c# :slight_smile:

3 Likes

Ecto feels a lot like C# linq when using the keyword syntax, which is possibly why I live using Ecto so much :smile:

after recently being reassigned back onto a .net core project, the slow edit -> compile -> test cycle in C# is horrible :stuck_out_tongue_winking_eye:

3 Likes

Very true, writing in Elixir is faster in that regard.

1 Like

I can’t lie, the transition has been difficult. Considering that VS is like a mother and static typing has many advantages for refactoring and such.
Even though .NET Core brought many improvements to the platform, the general flow of development does not pleases me anymore. I got to the point where many of my web apps were using the same combo: ASP.NET Core + MediatR (CQRS pattern) + AutoMapper; so I didn’t feel like there was anything new to learn or even other exciting ways to do stuff - everything was kinda dull. Don’t get me wrong, I still think C# is a great language and I work fulltime as a backend developer using it, but you know, I’m kinda saturaded after 5 years of the same - I need fresh air :slight_smile:.

3 Likes

Ecto feels a lot like C# LINQ when using the keyword syntax, which is possibly why I live using Ecto so much :smile:

Yep, it is really similar, but I’d rather use the fluent syntax (if Ecto had something like that).

after recently being reassigned back onto a .net core project, the slow edit → compile → test cycle in C# is horrible :stuck_out_tongue_winking_eye:

Just the fact that I have found myself writing a lot less boilerplate code is a big win for Elixir + Phoenix. I’m amazed how everything is proving itself a lot less easy than I first thought.

3 Likes