我有一个简单的ASP.NET Core 2.0 + Entity Framework Core项目:
我有一个名为ApplicationUser
的实体,它扩展了Microsoft.AspNet.Identity.IdentityUser
,而ApplicationUser有一个名为Books
的另一个实体的集合。
但是,当我尝试从UserUser中检索书籍集合后,从UserManager中检索它:
ApplicationUser user = await _userManager.GetUserAsync(User);
return user.Books;
我得到一个空集合。
如果我改为:
ApplicationUser user = await _userManager.GetUserAsync(User);
return _context.Users.Include(d => d.Books).FirstOrDefault(u => u == user);
然后我得到了正确的图书集。
我怀疑这是因为我从ApplicationUser
检索到的UserManager
缺少正确的DbContext
。 我的问题是,有更好的方法吗?就像以某种方式能够从用户那里获得集合而不必通过LINQ的DbContext?是否会有显着的性能提升?
最后,关于EF Core如何理解它如何在引擎盖下工作会有什么好读?
答案 0 :(得分:1)
首先,如果要从数据库访问数据,则必须使用DBContext。其次,您仍然可以从另一个对象访问数据库的唯一方法是,对象是直接或间接从数据库返回的类型IQueryable
。
例如,以下内容将返回IQueryable<User>
:
var users = _context.Users.Where(u => u == user);
这意味着您可以访问users
变量并访问数据库,如下所示:
var books = users.Select(u => u.Books);
请注意_userManager.GetUserAsync(User)
函数不会返回IQueryable
。这意味着ApplicationUser user
将仅包含其获取的内容(用户对象)。简单地使用user.Books
将无法帮助它从数据库中获取数据。此外,如果我没有弄错的话,GetUserAsync
从当前的声明主体而不是数据库中获取数据。无论哪种方式,当您尝试获取用户时,实体框架也不会自动获取Books。这是因为Igor提到由于延迟加载。 https://docs.microsoft.com/en-us/ef/core/querying/related-data
至于如何优化您的方式,您可以检查在控制台中运行的确切SQL查询。我已经展示的上述方法肯定会运行一个查询,因为ef核心会将这些行放在一起并准确理解要运行的查询。访问相同数据的简单方法类似于
_context.Books.Where(b => b.User == user)
如果您打算使用user
,则使用_userManager.GetUserId()
会有更好的性能,因为它只会从您的声明中获得一个值。然后你可以使用:
_context.Books.Where(b => b.UserId == userId)
答案 1 :(得分:0)
在此处为EF Core 2.1(Identity 4+)添加答案。
此答案基于延迟加载。有关其他方法,请参阅文章末尾。
Tseng对问题进行了评论,当时是针对EF 2.1预览版的。 2.1现在是RTM,如果您升级到EF Core 2.1,那么他发布的链接确实是您的答案。
它真的也很容易使用。按照提到的same link Tseng上的用代理进行延迟加载的指示,基本上可以做到这一点(假设您已按照链接所述正确地使用“虚拟”定义了模型):
在您的.AddDbContext<...>(...)
或OnConfiguring()
中,向.UseLazyLoadingProxies()
添加呼叫
例如,在Startup.cs
中:
services.AddDbContextPool<ApplicationDbContext>(options =>
options.UseMySql(Configuration.GetConnectionString("ApplicationDbContext"))
.UseLazyLoadingProxies()
);
重建。而已。除了使用代理外,还提到了其他方法,但这是最简单的。
使用以下方法检索数据:
var user = await _userManager.GetUserAsync(ApplicationUser);
var addresses = user.UserAddresses;
具有类似的型号:
public class ApplicationUser : IdentityUser<int>
{
public ApplicationUser()
{
UserAddresses = new List<UserAddress>();
}
public virtual ICollection<UserAddress> UserAddresses { get; set; }
}
public class UserAddress
{
public int UserAddressId { get; set; }
public int Id { get; set; }
...
public virtual ApplicationUser User { get; set; }
}
如果您喜欢使用急切加载或显式加载,则same link包含详细信息。我只是不在这里翻阅。