Transcript
-
So whenever it comes to relationships, we have half of the picture taken care of. We have our IDs in place on our tables
-
that inform that one table relates via that ID to another table. For example, this user ID informs us that one row
-
inside of our profiles table relates to one particular user who has whatever ID is inside of this column for that row.
-
So if we have a profile row with a user ID of one, that profile row relates to the user with the ID of one. If the user ID is two, that profile relates to the user with an ID of two,
-
so on and so forth. And that's the database side of the relationship. We also have foreign keys in place to enforce data integrity so that we cannot relate to a user
-
that doesn't actually exist inside of the users table from our profile. But how does this relationship come into play whenever we start talking about the Lucid ORM?
-
It would be nice if we had the ability to work with our user record directly from our profile model instance and vice versa, be able to work with our profile
-
for whatever user model instance we are working with. Well, good news, that's actually how the Lucid ORM works whenever it comes to relationships. All that we need to do is inform it
-
what we want that relationship to be named and the applicable properties that the relationship should use to map that relationship together. I like to put all of my Lucid relationship definitions
-
down at the bottom of the model underneath our column properties. And this will look relatively similar to how we're declaring our columns, except it will use its own special decorators.
-
So here we have a profile with the user ID that belongs to a user record. So with that verbiage in mind,
-
we can define this relationship using @belongsTo, there's our decorator right there, and that's going to import from AdonisJS Lucid ORM.
-
And then inside of this belongsTo decorator, we're going to want to provide it an instance of our user model. So we'll provide this as a callback function
-
and then provide it a direct instance to our user model just like so. I tab to auto import that from our user model itself. And then we'll want to declare the property
-
that we want this relationship to be housed on. For this, it would make most sense to call this property user. And the type for this user is going to be belongsTo,
-
and this will be provided the type of our user model. And we're getting a red squiggly on our belongsTo, but that's because it wants it to be imported
-
with import type rather than a namespace import. So we'll scroll up and decorate this with type just like so, and everything should be A-okay. And you'll also notice that that imported
-
from AdonisJS Lucid types relations instead of AdonisLucid ORM. And that's it. That's how we define our relationship from our profile to our user.
-
Now, there are some defaults being applied here to make this work automatically for us. If we need to change those defaults at all, we can provide a second argument into the belongsTo decorator.
-
And you'll see that this is an option set of the type relation options. With belongsTo, the one that's going to apply is going to be the foreign key.
-
The foreign key with belongsTo is the relationship key that is on the model we're presently working with. So that's going to be our user ID.
-
So we can specify that in here just like so. However, our relationship is directly working with a model called user, and this model's primary key is ID.
-
And that's how AdonisJS is going to map the default for this foreign key altogether. So in turn, we are actually making use of the default already,
-
so we can keep things nice and clean and remove that just like so. So that will allow us to load in our user relationship whenever we're working with our profile model. Let's take care of the inverse side
-
so that we can work with our profile model from our user model as well. So let's jump over to our user model. We'll scroll down to the end of our model column declarations.
-
And our user profile relationship is a one-to-one type. So our profile belongs to one user and our user has one profile.
-
So anytime that the property of the relationship is on the model itself, that's where we'll want to use belongsTo. On the inverse side, we just need to describe
-
how many is expected to exist for that relationship. In this case, we expect it to have one. So we can decorate it with a decorator, noting that accordingly. And in this particular case,
-
that decorator is called as one. So we'll import that. And this works very similar to belongsTo. We provide it in a callback function that returns the related model.
-
In this case, that's going to be our profile model. We'll declare a property that we want this relationship to be housed on. And in this case, it would make most sense to call this our profile.
-
And we'll define it the type has one. That is a type of our profile model. Looks like the auto import for these relationships does not like to import with type.
-
So we'll go ahead and populate that on there as well. And now we'll be able to populate a profile directly for any user that we're working with from our user model. Just like with belongsTo, we could provide a second argument
-
to this has one decorator, which are option sets that allow us to define what this relationship should use to relate to one another. All of the other relationship decorators and types
-
are going to be the inverse of belongsTo. Where belongsTo, we were making use of the foreign key
-
to relate to the property that is on this particular model. So right here, our user ID is there. On all of the other relationship types,
-
the foreign key is going to relate to the profile that is on the relationship model. So in this case, our foreign key would be our user ID
-
that is existent on our profile model. So whenever you're working with a one-to-one relationship, the has one would use foreign key to specify the column that it would work with on the related model.
-
And belongsTo would specify the foreign key for the relationship column that it would work with on the current model that we are on. Again, though, with how we have everything set up, we can make use of just the defaults
-
since our model name is user and the primary key for that model is ID, and it will concatenate them together as such to comprise the default value for this relationship. So we're good there.
-
And the same thing is true with our has one decorator as well. The model that we're relating to is our user model and the primary key for that model is ID. So this too will use the default as well.
-
So we can get rid of that altogether there.
Defining One to One Relationships Within Lucid Models
We'll learn how to define one-to-one relationships within our Lucid Models. We'll learn about the belongs to and has one decorators, their options, and types that make this possible.
Join the Discussion 4 comments
-
Hello Tom,
I'm used to working with Doctrine (ex Symfony users!) as an ORM, but I must admit that Lucid works a bit differently and I'm a bit confused about the need to keep both the userId declaration and the user relationship. Can't we just use the user relationship?
1-
Responding to noctisy
Hi noctisy!
With Lucid, relationships work with and directly read off of the model. So, if you omit the
userId
but define the relationship, you'll end up getting an exception.Though I don't know the core team's exact reasoning, I'd imagine it is so the relationship can make use of the column decorator's mutations to build out the relationship columns. It could also be for compatibility with hooks as well.
For example, you might want a different naming convention in the model than in the table.
export default class Profile { @column({ isPrimary: true }) declare id: number @column({ columnName: 'profile_user_id', // column name in db serializeAs: null, // omit from serialization (maybe it is confidential) }) declare userId: number @belongsTo(() => User) declare user: BelongsTo<Typeof User> }
Copied!2-
Responding to tomgobich
Thank you a lot for the clarification Tom! It was a bit confusing at first but after a second watch of the whole relationship part (5.0 → 5.13), it's more clear. Thanks for the resources too!
1-
Responding to noctisy
Awesome & anytime! I'm happy to hear things are clicking for you. If there is anything you feel would help make things clearer for the first go around, I'm all ears!! 😊
2
-
-
-