I have a custom users table in my database and i want to create a one-to-one relationship with aspnetusers table so that when i register a new customer, applicationuser class th
When working with one-to-one relationship, Entity Framework uses the parent's Id
column in the child as the FK to the parent, it won't create a second column for FK because that would be considered one-to-many relationship, because that second column would allow a parent Id
to exist in many child entries, whereas the PK as FK wouldn't.
Since your ApplicationUser
inherits from IdentityUser
, it will use it's existing properties and relationships. It already defines an Id
column, so creating UserId
is not necessary, as well as trying to make UserId
the key property. You should use the existing Id
column, which by default is string
and it looks your existing User
table has an integer
PK, so they don't match.
However, this is not the end of the world. Identity's built-in implementation uses string
as key for their classes (AspNetUsers, AspNetRoles, etc...) but they allows us to use another type of primary key.
Identity defines two classes for each table, so there are two IdentityUser
classes, two IdentityRole
, and so on. One is the base generic class, which accepts some generics. The other is the built-in implementation of that base class, which supplies those generic types.
This base class looks like this:
public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
where TLogin : IdentityUserLogin<TKey>
where TRole : IdentityUserRole<TKey>
where TClaim : IdentityUserClaim<TKey>
The first generic type is TKey
, which defines the key's type, which is string
. The second is a TLogin
, which is a IdentityUserLogin<TKey>
, which means it should be some class inheriting IdentityUserLogin
using the same TKey
type used as key (maybe string
, maybe an int
).
Meanwhile, the built-in implementation for these base classes looks like this:
public class IdentityUser
: IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser, IUser<string> {}
Which defines TKey
as a string
to be used as key. The other generics like IdentityUserLogin
and IdentityUserRole
, are built-in classes implementing the base classes which a string
key. Take a look how IdentityUserRole
looks like:
public class IdentityUserRole IdentityUserRole<string> {}
See? string
as well. Many other classes use string
as default for TKey
.
So if you were to change your class like this:
public class ApplicationUser : IdentityUser<int, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
{
public virtual User user { get; set; }
}
It wouldn't work yet, because we changed TKey
to be int
, but the built-in IdentityUserLogin
still uses string
. So we need to create our own IdentityUserLogin
like this:
public class MyNiceUserLogin : IdentityUserLogin<int>
{
}
...and use it like this:
public class ApplicationUser : IdentityUser<int, MyNiceUserLogin, IdentityUserRole, IdentityUserClaim>
{
public virtual User user { get; set; }
}
...but we still had to do the same with the other classes like IdentityUserRole
and IdentityUserClaim
.
int
. Now what about one-to-one relationship?Your code here:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>()
.HasRequired(i => i.user).WithRequiredDependent(i => i.appUser);
}
...works fine. You're configuring in a way both must exist, there is no ApplicationUser
without a User
and vice-versa.
Now, I recommend you read this Stack Overflow answer to know exactly what steps to follow in order to change Identity's classes to use int
as key.
I also strongly recommend you to read this post by John Atten, so you can understand deeply about how to customize/extend Identity.