ASP.NET Core 2 Identity/Entity Framework — как получить настраиваемые свойства в классе User?

В настоящее время я получаю пользователя с помощью:

ApplicationUser currentUser = await _userManager.GetUserAsync(User);

но я обнаружил, что таким образом он не содержит пользовательских свойств, например:

public virtual UserImage UserImage { get; set; }

поэтому каждый раз, когда мне нужно получить такое свойство, я пишу метод для получения из базы данных с помощью Entity Framework, например:

public async Task<UserImage> GetUserImage(string userId) =>
        await _dBcontext.UserImage.SingleOrDefaultAsync(u => u.ApplicationUserId == userId);

I would like to cache within the application(on the server, not cookie) all the user properties by only calling

await _userManager.GetUserAsync(User);
There is such a way?


person Eugene    schedule 29.01.2018    source источник


Ответы (2)


Я предполагаю, что вы на самом деле используете Entity Framework Core, хотя ваш вопрос помечен просто как entity-framework. Причина в том, что то, что у вас есть, будет естественным образом работать с Entity Framework, тогда как с Entity Framework Core оно определенно не будет работать вообще.

Основное различие между ними заключается в том, что EF Core не поддерживает отложенную загрузку. Благодаря свойствам виртуальной навигации EF динамически создается прокси-класс, производный от вашего класса сущностей. Затем свойства навигации динамически переопределяются, чтобы добавить к геттерам логику отложенной загрузки EF. Это приводит к тому, что доступ получателя свойств вызывает указанную логику ленивой загрузки и выдает запрос к базе данных для материализации связанного объекта или объектов.

Поскольку EF Core не поддерживает отложенную загрузку, ничего из этого не происходит. В результате, если вы не загрузите отношение явно или нетерпеливо, оно останется нулевым. Тем не менее, отложенная загрузка — плохая идея. Это может привести к огромной неэффективности, такой как проблема с запросом 1+N, когда, например, вы выполняете итерацию по списку и в конечном итоге выполняете запрос для каждого элемента в списке, чтобы материализовать некоторую связь в этом элементе. Если у вас много элементов, вы можете в конечном итоге выдать массу запросов, особенно если в дереве есть другие отношения. Скажем, например, что у вас есть список элементов со связанным объектом, а затем у самого связанного объекта есть связанный объект, к которому вам нужно получить доступ. Теперь вы каждый раз выдаете еще больше запросов на получение этого связанного объекта. Он может очень быстро выйти из-под контроля.

Длинные и короткие, гораздо лучше жадно загружать нужные вам отношения. Это фактически приведет к тому, что JOIN будут выданы в начальном запросе для получения всех отношений одновременно, только в этом одном запросе. Если не считать этого, явная загрузка по-прежнему предпочтительнее, поскольку, по крайней мере, вы тогда будете знать о конкретных запросах, которые вы выдаете, и можете четко видеть, если что-то начинает выходить из-под контроля.

UserManager, тем не менее, не дает вам возможности выполнять интенсивные нагрузки. В результате, если вы используете его для получения пользователя, единственным вариантом является явная загрузка связанной сущности. Однако это не обязательно плохо, так как это всего лишь один дополнительный запрос.

var currentUser = await _userManager.GetUserAsync(User);
await _dbContext.Entry(currentUser).Reference(u => u.UserImage).LoadAsync();

Теперь вы можете получить доступ к связанному изображению.

В качестве альтернативы вы можете вместо этого запросить пользователя из контекста, а затем одновременно загрузить изображение:

var currentUser = await _dbContext.Users.Include(u => u.UserImage).SingleOrDefault(u => u.Id == User.Identity.GetUserId());

Это выдаст только один запрос с соединением отношения изображения.

person Chris Pratt    schedule 29.01.2018

Взгляните на эту тему: форум asp.net

Правила ленивой загрузки:

context.Configuration.ProxyCreationEnabled должно быть правдой. context.Configuration.LazyLoadingEnabled должно быть правдой. Свойство навигации должно быть определено как public, virtual. Контекст НЕ будет выполнять ленивую загрузку, если свойство не определено как виртуальное.

Я надеюсь, это поможет ;)

person Andrea    schedule 29.01.2018