I am using ASP.NET Core targeting NET6.0 using the Microsoft.AspNetCore.Identity
user management system with EntityFrameworkCore
.
I have a custom dependent entity (Players
) which I want to link to my custom ApplicationUser
class in a one-to-one relationship. Every AspNetUsers
record has an associated single record in the previously existing my_db_schema.tblPlayers
database table. The AspNetCore identity tables are in the same database. Both are populated with real data (This project is to migrate from AspNetIdentity
to AspNetCore.Identity
)
[Table("tblPlayers", Schema = "my_db_schema")]
public class Players
{
//[Key]
public int Id { get; set; }
public string PlayerName { get; set; }
//[ForeignKey("User")]
public string UserId { get; set; }
public ApplicationUser User { get; set; }
}
The UserId
is a foreign key to the Id
column on the AspNetUsers
table. The Id
column is a primary key.
My custom ApplicationUser
class is defined as this:
public class ApplicationUser : IdentityUser<string>
{
public Players Players { get; set; }
}
In my custom ApplicationDbContext
OnModelCreating
function, I have the following:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Players>().HasKey(t => t.Id);
modelBuilder.Entity<ApplicationUser>()
.HasOne<Players>(s => s.Players)
.WithOne(u => u.User)
.HasForeignKey<Players>(ad => ad.UserId).HasPrincipalKey<ApplicationUser>(x => x.Id).IsRequired();
}
I am not interested in any automatic removal/management of data in the tblPlayers
database table. I am not interested in running migrations or scaffolding. All that I need is that for any place in my code where I get an instance of an ApplicationUser
, that the Players
property is populated with data from the tblPlayers
database table. No matter what combination of fluid API, or annotations I use, the ApplicationUser.Players
property is always null, and the rest of the ApplicationUser
properties are populated as expected.
I have seen these articles:
Why custom properties for IdentityUser custom class are always null
Custom property is null IdentityUser
But both of these require a specific instantiation of the custom ApplicationUserManager
class. I would like to avoid having to do that in all areas of my code where ApplicationUserManager
is referenced if possible.
Please help :)
CodePudding user response:
Implementing a custom UserManager
is trivial -
public class CustomUserManager : UserManager<User>
Then register it at startup
services.AddIdentity<User, Role>()
.AddUserManager<QuestUserManager>()
From there you'll just inject the custom user manager class where you need it.
public class SomeController : Controller {
private readonly CustomUserManager _userManager;
public SomeController(CustomUserManager userManager)
{
_userManager = userManager;
}
}
The only way you'll get the Players
property populated is to override the method(s) that return a User
and add .Include(u => u.Players)
to the EF Core queries - something like
public override async Task<User> FindByIdAsync(string userId)
return await Users.Include(u => u.Players).SingleOrDefaultAsync(u => u.Id == userId);
}
CodePudding user response:
You don't have to create your own custom UserManager
in order to do that. But @Mr.T is right, it is necessary to include the dependant table in order to retrieve records filled.
So you have 3 options, except creating a custom UserManager
:
- In case you are following the
Repository
pattern you would do something like the following:
//Yor 'UserRepository' or whatever
public async Task<List<ApplicationUser>> GetUsers()
{
var set = _context.Set<ApplicationUser>()
.Include(user => user.Players);
return await set.ToListAsync();
}
In case you are using the DbContext directly - you would basically do the same as within the method above.
And in case you are using the default
UserManager
:
var filledUsers = await _userManager.Users.Include(user => user.Players).ToListAsync();