Пользовательские объекты с идентификацией сети asp (один ко многим)
Когда я загружаю пользователя с помощью диспетчера пользователей
private UserManager<MyUser> GetUserManager()
{
var userStore = new UserStore<MyUser>(_context);
return new UserManager<MyUser>(userStore);
}
public MyUser GetUser(string username)
{
return GetUserManager().FindByName(username);
}
моя сущность UserAddress заполнена, но мои сущности AddressType и Country в UserAddress равны нулю.
Однако, используя это для загрузки пользователя, все объекты заполняются. Все, что я делаю здесь, это доступ к сущностям, но ничего с ними не делаю.
public MyUser GetUser(string username)
{
var addressTypes = _context.AddressType.ToList();
var countries = _context.Countries.ToList();
return GetUserManager().FindByName(username);
}
Также включение отложенной загрузки работает, как показано ниже.
public MyUser GetUser(string username)
{
_context.Configuration.LazyLoadingEnabled = true;
var user = GetUserManager().FindByName(username);
_context.Configuration.LazyLoadingEnabled = false;
return user;
}
Итак, почему сущности обнуляются с отложенной загрузкой, но они работают, если я просто получаю к ним доступ в контексте, но ничего не делаю с ними?
Я использую DB First. Вот мои сущности (важные биты)
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; }
}
1 ответ
Вы как бы ответили на свой вопрос здесь. При отложенной загрузке база данных запрашивает запрашиваемую информацию при доступе к ней с использованием точечной нотации. Так что в вашем примере доступ user.AddressType
фактически сделает еще один запрос к БД, чтобы получить AddressType, связанный с этим пользователем, и сохранить его в контексте.
С отключенной отложенной загрузкой и запросом БД для AddressTypes и стран вы затем тянете в DbContext, поэтому при доступе к соответствующей информации, т.е.user.AddressType
, AddressType для этого пользователя уже загружен в DbContext, поэтому он будет использовать его и не должен будет запрашивать базу данных. без предварительной загрузки они всегда будут нулевыми.
Если вы всегда хотите добавить эти связанные таблицы, вам нужно изменить запрос, чтобы использовать .Include()
метод. Для этого вам нужно извлечь из UserStore и переопределить метод FindByName следующим образом.
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)
}
}
затем используйте этот новый магазин в вашем UserManager
private MyUserManager GetUserManager()
{
var userStore = new MyUserStore(_context);
return new UserManager<MyUser>(userStore);
}