【发布时间】:2021-07-26 04:32:14
【问题描述】:
我有点不明白为什么这段代码不起作用。我有一个基本的一对多关系,我加载一个父母并包括它的孩子。后来我试图从孩子导航回父母,但父母是空的,我不知道为什么。
问题:
为什么我不能查询父/子对象的图表并在它们之间从子对象向后导航到父对象?父级始终为空。
这是实体。
public class Budget
{
[Key]
public int Id { get; set; }
public ICollection<Expense> Expenses { get; set; }
public ICollection<Income> Incomes { get; set; }
}
public class Expense
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[StringLength(200)]
public string ExpenseName { get; set; }
[Required]
public decimal Cost { get; set; }
[StringLength(800)]
public string Notes { get; set; }
public DateTime? DueDate { get; set; }
public Budget Budget { get; set; }
}
public class Income
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public decimal Amount { get; set; } = 0;
[Required]
[StringLength(200)]
public string Source { get; set; }
[Required]
public DateTime? PayDate { get; set; } = DateTime.Now;
public Budget Budget { get; set; }
}
这是存储库查询。
public async Task<Budget> GetBudget(int id)
{
try
{
return await context.Budget
.Include(e => e.Expenses)
.Include(i => i.Incomes)
.SingleAsync(b => b.Id == id);
}
catch(Exception x)
{
x.ToString();
}
return null;
}
我希望能够通过从费用到预算的关系重新导航以获取 Budget.Income 集合。
预期结果:
foreach(Expense expense in Budget.Expenses)
{
if (expense.Budget is not null)
{
ICollection<Income> paychecks = expense.Budget.Incomes; // Why is Budget always null?
}
}
我希望即使我不使用 ThenInclude(e => e.Budget),我仍然应该能够从子导航回到父 {var budget = fee.Budget}。我很惊讶这不起作用。
我没有在此处包含收入实体,但我的目标是遍历费用.Budget.Incomes 以获取我只能访问费用实例的代码中的收入集合。
删除 ThenInclude(e => e.Budget) 后我不再收到错误,但费用.Budget 属性仍然为空。
更新
我相信我找到了问题的根本原因。当我将属性 Budget 添加到 Expense 类时,反序列化来自 API 的对象时开始出现错误。由于循环引用,HttpClient 抛出错误。
因为我正在获取根预算实体及其相关费用,并且费用有对预算的引用,所以我得到了周期性引用错误。
我将此代码添加到启动 Blazor 服务器启动类以修复它。我想这是我的问题。
services.AddControllersWithViews().AddJsonOptions(x =>
x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles);
如果我更改为 ReferenceHandler.Preserve 我会得到一个不同的错误。
'JSON 值无法转换为 System.Collections.Generic.ICollection`1[BlazorApp.Data.Models.Expense]。路径:$.expenses |行号:0 | BytePositionInLine:34。'
我不知道但想解决的是如何进行这项工作,以便我可以获得预算 -> 费用并让 Expense.Budget 属性指向它的父预算实例。我真正的问题可能与 json 序列化和反序列化更相关。
【问题讨论】:
-
实体模型有问题。
Income.Expenses集合的目的是什么以及它是如何映射的? -
嗯,这就是你的想法。但是我(根据我的 EF Core 经验,正如您从我的个人资料中看到的那样)发现该确切属性存在问题,因为它会破坏关系,并且可能是您遇到问题的原因。
-
@IvanStoev 是的,我同意你的看法。
-
至少它清楚地表明您应该始终显示重现问题的代码。我想知道你问题的第一个版本是否有。该版本看起来不错,但仍然触发了一个带有错误的长镜头答案,然后是一长串编辑(问题和答案)导致无处可去,但所有这些都表明您仍在开发您的代码。我建议您返回一个您已测试的最小示例来重现该问题。
-
重点是 - 你要问的是证明可以在 EF Core 中工作,所以显然你的真实模型/配置有问题。我敢打赌,有些东西你还没有展示出来。最初的错误消息(您已删除)非常清楚 - “表达式 'e.Budget' 在 'Include' 操作中无效,因为它不代表属性访问:” 这可能发生例如,如果你用
[NotMapped]装饰Budget属性。许多人这样做,然后忘记提及那个“小”细节。那么,你有类似的东西吗?还是流畅的配置代码?
标签: entity-framework entity-framework-core