Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
299 views
in Technique[技术] by (71.8m points)

c# - Custom entities with asp net identity (one-to-many)

When I load a user using the User Manager

private UserManager<MyUser> GetUserManager()
{
    var userStore = new UserStore<MyUser>(_context);
    return new UserManager<MyUser>(userStore);
}

public MyUser GetUser(string username)
{
    return GetUserManager().FindByName(username);
}

my UserAddress entity is populated, but my AddressType and Country entities in the UserAddress is null.

However using this to load a user and all entities are populated. All I do here is access the entities but don't do anything with them.

public MyUser GetUser(string username)
{
    var addressTypes = _context.AddressType.ToList();
    var countries = _context.Countries.ToList();        
    return GetUserManager().FindByName(username);
}

Also enabling lazy loading works like below.

    public MyUser GetUser(string username)
    {
        _context.Configuration.LazyLoadingEnabled = true;
        var user = GetUserManager().FindByName(username);
        _context.Configuration.LazyLoadingEnabled = false;
        return user;
    }

So why are the entities null with lazy loading off but they work if I just access them in the context but do nothing with them?

I'm using DB First. Heres my entities (the important bits)

public class MyUser : IdentityUser
{
    public MyUser()
    {
        this.Address = new List<UserAddress>();
    }

    public virtual IList<UserAddress> Address { get; set; } 
}

[Table("AddressTypes")]
public partial class AddressTypes
{
    public AddressTypes()
    {
        this.Address = new List<UserAddress>();
    }
    public int Id { get; set; }
    public virtual IList<UserAddress> Address { get; set; } 
}

[Table("Country")]
public partial class Country
{
    public Country()
    {
        this.Address = new List<UserAddress>();
    }
    public int Id { get; set; }
    public virtual IList<UserAddress> Address { get; set; } 
}

[Table("UserAddress")]
public partial class UserAddress
{
    public int Id { get; set; }
    public string UserId { get; set; }
    public int AddressTypeId { get; set; }
    public int CountryId { get; set; }
    public AddressTypes AddressType { get; set; }
    public Country Country { get; set; }
    [ForeignKey("UserId")]
    public MyUser User { get; set; }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You've kind of answered your own Question here. With Lazy Loading, the database is re-queried for the requested information when you access it using the dot notation. So in your example accessing user.AddressType would actually make another request to the DB to get the AddressType associated to that user and store it in the Context.

With Lazy Loading turned off, and you querying the DB for the AddressTypes and Countries, you are pulling then into the DbContext so when you access the related information i.e.user.AddressType, the AddressType for that user is already loaded into the DbContext, so it will use that and not have to requery the database. without prefetching them, they will always be a null.

If you always want to bring in those related tables, then you will need to modify your query to use the .Include() method. For this you will need to derive from UserStore and override the FindByName method like so.

public class MyUserStore : UserStore<MyUser>
{
    public MyUserStore(DbContext context) : base(context)
    {
    }

    public override MyUser FindByName(string userName)
    {
        return Users.Include(x=>x.AddressType).Include(x=>x.Country).FirstOrDefault(n=>n.UserName == userName); 
        //you may need to also include the following includes if you need them
        //.Include(x=>x.Roles).Include(x=>x.Claims).Include(x=>x.Logins)
    }
}

then use this new Store in your UserManager

private MyUserManager GetUserManager()
{
    var userStore = new MyUserStore(_context);
    return new UserManager<MyUser>(userStore);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...