c# - 在 Blazor 中登录后使用实体框架返回的对象未完成
问题描述
问题描述如下,首先我给你看代码。
在我的 Blazor 应用程序的数据库中,有三个表:Factor、FactorEntry、EntrySet。
一个 EntrySet 包含多个属于一个 Factor 的 FactorEntry。
以下是相关的模型类:
public class Factor
{
public int FactorId { get; set; }
public string FactorName { get; set; }
...
public virtual ICollection<FactorEntry> FactorEntry { get; set; }
}
public class FactorEntry
{
public int FactorEntryId { get; set; }
public int EntryValue { get; set; }
public int FactorId { get; set; }
public virtual Factor Factor { get; set; }
public virtual EntrySet EntrySet { get; set; }
}
public class EntrySet
{
public int EntrySetId { get; set; }
public DateTime EntrySetDate { get; set; }
public string UserId { get; set; }
public virtual ICollection<FactorEntry> FactorEntries { get; set; }
}
这是我用来为特定日期和用户请求 EntrySet 的方法:
public async Task<EntrySet> GetEntrySet(DateTime date, string userID)
{
var entry = await _context.EntrySets
.Include(entry => entry.FactorEntries)
.Where(d => d.EntrySetDate.Date == date.Date)
.Where(u => u.UserId == userID)
.FirstOrDefaultAsync();
return entry;
}
在我的 Index.razor 有一个日期选择器。当日期更改时,我为选择的日期和登录的用户调用 GetEntrySet 方法。 OnInitialized 我将 Datepicker 的日期更改为当前日期。
<InputDate @bind-Value="this.ChoosenDate" />
@code{
public EntrySet CurrentEntrySet { get; set; } = new EntrySet() {
FactorEntries = new List<FactorEntry>()
};
private bool entryExisted;
private DateTime choosenDate;
public DateTime ChoosenDate
{
get { return choosenDate; }
set
{
choosenDate = value;
this.DateChange();
}
}
public string UserID { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
var principal = httpContextAccessor.HttpContext.User;
this.UserID = principal.FindFirstValue(ClaimTypes.NameIdentifier);
ChoosenDate = DateTime.Now;
}
private async Task DateChange()
{
if (String.IsNullOrEmpty(this.UserID))
{
Console.WriteLine("NoUserID");
}
else
{
var entrySetForDate = await service.GetEntrySet(this.choosenDate, this.UserID);
if (entrySetForDate == null)
{
this.entryExisted = false;
await this.CreateNewEntrySet();
StateHasChanged();
}
else
{
this.entryExisted = true;
CurrentEntrySet = entrySetForDate;
StateHasChanged();
}
}
}
主要问题
一切正常。我使用 datepicker 更改日期,GetEntrySet 返回正确的 EntrySet,包括所有 FactorEntry 和相关的 Factor。
但是有一种情况会导致问题:在登录之后(使用 ASP.net Core Identity),在 OnInitialized 中更改日期时。GetEntrySet 返回正确的EntrySet,具有正确的FactorEntry 列表,但FactorEntry 中的Factor 为Null。
我不知道,为什么会这样。有什么线索吗?
附带问题
正如您在代码中看到的,我在 ChoosenDate 的 Set{} 中调用了异步方法 DateChange(),该方法绑定到了日期选择器。在 Set{} 中,我等不及了。知道我该如何改变吗?
问候斯特凡
解决方案
跳出来的一件事是,当您急切加载 FactorEntries 时,您并没有急切加载它们下面的 Factor:
var entry = await _context.EntrySets
.Include(entry => entry.FactorEntries)
.ThenInclude(fe => fe.Factor)
.Where(d => d.EntrySetDate.Date == date.Date)
.Where(u => u.UserId == userID)
.FirstOrDefaultAsync();
如果您想在客户端和服务器之间传递实体,我建议尽可能避免双向引用。被序列化后,它们可以达到一个深度,引用将被保留为#null。我假设您可能已禁用延迟加载以帮助避免序列化程序触发读取。由于在您阅读条目时 DbContext 是否恰好在跟踪因子,您可能会遇到类似这样的间歇性或情境问题。禁用延迟加载后,当您使用其 FactorEntries 集合加载条目集时,当它填充每个 FactorEntry 时,它仍将通过其缓存查看是否跟踪了任何引用的 FactorId,如果可用,它将填充这些引用。
对于 Blazor,我怀疑 DbContext 在视图刷新之间存在一定的寿命(希望不会在会话之间共享),因此通常情况下,当您请求条目时,因素很有可能在正常条件下被加载,但是在第一次登录时,可能尚未阅读该用户条目的因素。如果是这种情况,我会对性能非常谨慎,具体取决于 DbContext 实例的存活时间。DbContext 跟踪的实体越多,读取和写入操作将继续获得越慢。
推荐阅读
- android - Android mvvm 我应该在两个视图中使用 2 个 ViewModel、1 个 ViewModel,还是在父活动中使用 1 个?
- powershell - 如何搜索特定文件名,然后使用 PowerShell 将该文件之后的所有文件移动到另一个文件夹
- nginx - Nginx Ingress 控制器抛出 400 Bad Request 错误
- python - django 模板循环两个查询集
- neo4j - 如何使用 APOC 在 Neo4j 中编写更高效的导入查询
- python - Python - 基于字符串匹配减少数据框字段的值
- python - 将 DataFrame 的最后 n 行添加到新列中
- android - 以编程方式设置 ImageView 的边距和其他布局属性
- ruby - 黄瓜。如何在 RubyMine 中为 RSpec 断言启用代码完成
- python - 网页抓取。列而不是行