A Deep Dive Into Relationship CRUD with Models
In this lesson, we'll take a deep look at how we can perform CRUD operations with one-to-one, one-to-many, many-to-one, and many-to-many relationships using our Lucid Models.
- Author
- Tom Gobich
- Published
- Apr 02
- Duration
- 18m 5s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
A Deep Dive Into Relationship CRUD with Models
-
[MUSIC]
-
So at this point, we know most of the big picture,
-
but there is one final piece of the puzzle to put together,
-
and that's how we combine our relationships together
-
with our models to actually create data with our models.
-
So I'm going to hit "Control tilde" here inside of
-
our text editor and this will bring up the terminal.
-
Now, I just have it taking up full screen,
-
you can adjust this right here.
-
This is going to give us a little bit more room to work with
-
compared to working directly inside of our terminal application.
-
I'm going to run node.ace.repl to jump into a REPL session.
-
Await.loadModels to load up our models.
-
So let's start with one-to-one relationships.
-
So let's create a brand new user.
-
So let's do const user equals awaitModels.user.read.
-
We'll pass in an object here.
-
I think this takes a full name.
-
I'll put my name here,
-
email, we'll just do [email protected],
-
and then a password of password.
-
Let's go ahead and run that.
-
Cool. So now we should have our user.
-
If we go ahead and serialize that,
-
we'll see my details printed out.
-
However, at present, if we go ahead and try to await
-
user.loadProfile and we do user.profile,
-
we're going to get null because we haven't
-
actually created a profile for this user.
-
With our factory, we have this creating
-
all of our profiles along with our users,
-
which is why we went ahead and created
-
a brand new user here so that we can walk through this.
-
So there's a couple of ways that we can actually add
-
data with a relationship for our user.
-
So we could do await user.related as we've
-
done prior to reach through the relationship,
-
and then provide the relationship name.
-
So that would be our profile.
-
So far, we've just used this to
-
access the relation query builder,
-
but we can also call create directly off of this as
-
well for relationships pointing to a single record.
-
We just provided an object
-
for the record that we want to create.
-
So from our user model,
-
we're grabbing the relationship for our profile,
-
and then we're going to create a new profile
-
specifically for the user that we started this call from.
-
Lucid will automatically bind this user's ID
-
onto the profile that ends up getting created.
-
So it will automatically set that user ID that's on
-
our profile model just via this relationship.
-
Meaning, all that we have to do is define the,
-
I think we call it the biography column,
-
and everything else will be automatically
-
taken care of for our current profile.
-
So this is my bio.
-
Let's hit "Enter" there.
-
Cannot define biography on profile model since
-
it's not defined as a model property.
-
So I got the name wrong, my bad.
-
Let's go check our profile model here.
-
Oh, it's called description.
-
We'll elevate our panel size back up for our terminal.
-
I'll go ahead and hit "Up",
-
and I'll switch our biography column to description.
-
Run that, and there we go.
-
So now if we await user.loadProfile,
-
and then user.profile,
-
and we go ahead and serialize that,
-
we're going to see that we actually get back
-
that newly created profile instance.
-
Additionally, whenever we called create,
-
it immediately returned the model
-
that was created as a result as well.
-
So you could do cost profile equals await
-
user related profile.create and get
-
back that brand new profile that way as well.
-
So let's go ahead and await user.profile.delete
-
to delete that user's profile.
-
So now if we do user.profile.isDeleted,
-
we're going to get back true.
-
Remember that this is a flag that holds whether or not
-
the current record has been
-
deleted out of the database using the model.
-
This paves way for us to create a brand new profile.
-
So I've cleared out our terminal,
-
reloaded our rep session to give us more working room here.
-
Let's go ahead and grab that user again.
-
So cost user equals awaitModelsUser.findByOrFail,
-
we'll find by e-mail,
-
and we've provided that with [email protected].
-
So now we should have our user, and if we type out user,
-
we could see in the hint down here that we do indeed have that user.
-
We can also create a brand new record by
-
instantiating the model itself as well.
-
So we can do const profile equals newModels.profile.
-
Within our code, I'm going to scroll down to the bottom here.
-
This would be the same as doing const profile
-
equals new profile directly with our model class.
-
So we'll run that on the profile.
-
We'll set the description value equal to,
-
we'll just do test right now to give it something.
-
So at this point, we have a profile instance of
-
our model and a user instance of our model,
-
but our profile instance is not persisted into the database,
-
nor is it bound to our user.
-
Well, we can do both of those with one call by doing
-
awaitUser.relatedProfile to reach through with the relationship again,
-
and calling .save and providing it
-
the entire model that we want to relate with,
-
which would be our profile.
-
This will both persist our profile into the database
-
and relate it to our user record as well.
-
So we've run this, and then awaitUser.loadProfile,
-
user.profile, let's go ahead and serialize that.
-
There is our brand new profile with our test description.
-
Once more, let's go ahead and awaitUserProfile.delete.
-
Back with a fresh slate here,
-
we have our user once more.
-
Another way that we can join these relationships together,
-
and this one is unique to belongs to relationships.
-
So this will be coming at it from our profile side,
-
is to use associate and disassociate.
-
So const profile equals new,
-
and let's do models.profile once more,
-
instantiating a new instance of our profile class.
-
Then we'll do profile.description equals,
-
I probably spelled that wrong,
-
but we'll just do associated there.
-
Now from our profile side,
-
we can awaitProfile.related,
-
reach for the user relationship,
-
and we can associate our profile
-
with the particular user instance that we have.
-
Again, this will save our profile into the database,
-
and set its user ID with the user's ID that we've provided in.
-
We'll go ahead and run that.
-
Now if we await,
-
and let's do this from our user side,
-
user.loadProfile, user.profile.serialize once more,
-
we'll see that our profile was successfully associated with this user.
-
Now, the user ID relationship for our profile is required.
-
But if this relationship were nullable,
-
we could then dissociate these two from one another as well,
-
by doing something relatively similar to our associate call.
-
We could awaitProfile.related user,
-
and then call.dissociate to pluck the two apart from one another,
-
essentially removing the user ID off our profile and setting it to null.
-
Again, our profile's user ID is required,
-
it's not nullable in the database.
-
So if I were to run this,
-
we're going to get an error due to that violation of the not null constraint.
-
But if that relationship were nullable,
-
that's one way that you could dissociate the two from one another.
-
So we're back into a fresh REPL session with everything cleared out.
-
Similarly to how we created a record through
-
the relationship for our one-to-one relationship between our user and our profile,
-
we can do the same using a create many call for one-to-many relationships as well.
-
So if we create a new Sinist here,
-
I'm going to do const me because I find Sinist rather hard to spell correctly,
-
equals awaitModels.sinist.create,
-
providing a first name of Tom and a last name of Govij.
-
So we'll just create a record here for myself.
-
I believe headshot URL has an empty string default,
-
so we should be good to just create a record with that.
-
Cool. Everything looks good there.
-
If we do await me.related,
-
and I'm going to collapse this back down and take
-
a look to see what we call this relationship.
-
We have moviesDirected and moviesWritten as our hasMany relationships here.
-
So we can do either one of those for our example,
-
moviesWritten.createMany here to create many in one go.
-
So we can provide in an array,
-
and then inside of our array,
-
we just need to create objects for however many movies we
-
want to add and fill them out with each movie's details.
-
So let's see, we have our status ID.
-
I'm just going to default that to one.
-
Our director ID,
-
we'll default that to one.
-
Our writer ID will be automatically set via the relationship because we're reaching
-
through this user via the movie's written relationship,
-
which is bound by the written ID.
-
So we can pass over the written ID,
-
go to title, do written by me or something like that.
-
I believe everything else there is optional.
-
So let's move on to our second one, status ID.
-
We'll just do one here, director ID.
-
We'll do one again, title,
-
written by me too.
-
Let's go ahead and run that.
-
As you can see, just like create,
-
it's going to return back each of the movies that was created with this relationship.
-
Now we should be able to do await me.loadMoviesWritten,
-
and then me.moviesWritten,
-
and we'll map over those,
-
movie.serialize like so,
-
and we get back both movies written by me and written by me too.
-
So we're back with a fresh REPL session with me defined once more.
-
Again, just like with our user profile example,
-
whenever we called save through the relationship,
-
we took a model instance that wasn't yet persisted into the database,
-
saved it, and bound it to the user all in one blow.
-
We can do that exact same thing here using save many for our one-to-many relationships.
-
So let's do const movie1 equals new models movie,
-
and we'll create a new instance of that.
-
Now, rather than doing movie1.statusId,
-
so on and so forth, taking up multiple lines here,
-
what we could alternatively do is do movie1.merge,
-
and this will merge whatever object data we provide into our current movie data.
-
So for example, we could just set just as we did with our create call,
-
our status, id of one.
-
How about for this one, we set these movies as directed.
-
So we'll set our writer ID rather than our director ID,
-
and then our title directed by me1,
-
and we'll merge that data in.
-
So now if we do movie1.title,
-
we see it was directed by me1.
-
Cool. So let's do const movie2 equals new models movie,
-
create an instance of that,
-
and we can do movie2.merge,
-
statusId of one,
-
writerId of two,
-
and title of directed by me2,
-
and we'll merge that in.
-
So now for movie2.title,
-
we have directed by me.
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!