I've this setup with code first model:
public class TestContext :IdentityDbContext<TestUser>
{
public TestContext()
: base("TestConnection")
{
this.Configuration.LazyLoadingEnabled = false;
}
public DbSet<Customer> Customers{get;set;}
}
public class TestUser : IdentityUser
{
public virtual Customer Customer { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName {get; set;}
}
I've extended the IdentityUser to contain an instance of "Customer" Class.
Now consider this code:
var user = UserManager.FindById("some id");
if (user != null)
{
string str=user.Customer.FirstName; //since lazy loading is off, user.Customer is null and hence gives null reference exception.
}
since lazy loading is off, user.Customer is null and hence gives null reference exception. I'll be glad if anyone can help me in accessing the Navigation Properties of IdentityUser when LazyLoading is off.
Thanks.
The advice is not to use lazy loading unless you are certain that it is the better solution. This is why (unlike in previous versions of EF) lazy loading is not enabled by default in Entity Framework Core.
To turn off lazy loading for all entities in the context, set its configuration property to false.
Explicit loading means that the related data is explicitly loaded from the database at a later time. Lazy loading means that the related data is transparently loaded from the database when the navigation property is accessed.
Lazy loading by default in Entity Framework We see that for “Timken eng” there are 2 in the location count. As we discussed, lazy loading is enabled by default.
If you are always wanting to load the related data without using Lazy Loading then you will need to write your own implementation of the UserStore
and plug that into your UserManager
. For example..
public class ApplicationUserStore : UserStore<TestUser>
{
public ApplicationUserStore(TestContext context) : base(context)
{
}
public override TestUser FindByIdAsync(string userId)
{
return Users.Include(c => c.Customer).FirstOrDefault(u => u.Id == userId);
//you may want to chain in some other .Include()s like Roles, Claims, Logins etc..
}
}
then when you create your UserManager, plugin this implementation of the UserStore
, and your Customer
data will be loaded with the user.. this may look something like..
public class TestUserManager : UserManager<TestUser>
{
public TestUserManager() : base(new ApplicationUserStore(new TestContext()))
{
}
}
depending on your project, the UserManager
implementation will be different.
I have solved with this:
Create a custom UserManager
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators, IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUser>> logger, IHttpContextAccessor contextAccessor) : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger, contextAccessor) { }
public override Task<ApplicationUser> FindByIdAsync(string userId)
{
return Users.Include(c => c.Esercizio).FirstOrDefaultAsync(u => u.Id == userId);
}
}
Replace default UserManager service
In your ConfigureServices add this:
services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders().AddUserManager<ApplicationUserManager>();
Change arguments for DI
from
[FromServices]UserManager<ApplicationUser> userManager
to
[FromServices]ApplicationUserManager userManager
I hope this helps
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With