I have an old ASP.NET MVC project that uses Identity/SQL Server which has worked fine for over a decade and am now attempting to begin a new version that uses ASP.NET Core.
I have extended the IdentityUser
into ApplicationUser
with some custom fields that are all coming in from the database fine. But I also have a foreign key to a separate entity that returns NULL no matter what I try. All of this worked fine in the old project.
ApplicationUser
class:
public partial class ApplicationUser : IdentityUser
{
public string CustomField { get; set; }
public Guid? EntityId { get; set; }
[ForeignKey("EntityId")]
public virtual EntityObject? Entity { get; set; }
}
Foreign key EntityObject
class:
[PrimaryKey("EntityId")]
public class EntityObject
{
[Key]
public System.Guid EntityId { get; set; }
public string Foo { get; set; }
public string Bar { get; set; }
}
DbContext
class:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
CustomField
is populated but EntityObject
is always NULL where it wasn't in the old project.
I have trawled through various threads here trying all different combinations (e.g. implementing OnModelCreating()
) and come to no avail. I am coming from a very much database-first background and as this is a legacy database migrations are difficult so am trying to avoid using as much as possible.
Update This is the code I am using to retrieve the user information and is where I see that the foreign key Entity object is null:
ApplicationUser user = userManager.GetUserAsync(User).Result;
I noticed in the generated SQL in the console that it only queries the AspNetUsers table and does not attempt a join
Entity Framework Core doesn't do lazy loading out of the box -- it can still be done, but be aware of the warning on above linked page --, instead, you have to specify which navigation properties to include/load -- here the Entity
property.
When you would be working directly with the ApplicationDbContext
that would look like below; notice the Include
statement.
var user = await dbc.Users
.Include(o => o.Entity)
.FirstOrDefaultAsync();
Since you're dealing with the ASP.NET Identity UserManager instead of directly with the ApplicationDbContext
, you can configure it to always eagerly load that Entity
navigation property, by configuring an AutoInclude
for given property in the OnModelCreating
override of your ApplicationDbContext
.
Link to the documentation.
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<ApplicationUser>().Navigation(e => e.Entity).AutoInclude();
}
From the AutoInclude
documentation:
Configures whether this navigation should be automatically included in a query.
Sidenote; don't use .Result
; instead await
given call.
var user = await userManager.GetUserAsync(User);
There's much info about this on StackOverflow.