当我保存更改时,一切看起来都很好。正确创建CaseWorkNote实体并将其添加到workNotes集合(Case实体的属性)。 当CurrentUnitOfWork调用DbContext-> SaveChanges()时,我看到我的实体在那里,状态为“已添加”。
最后,什么都没有保存到DB。
我在代码中错过了什么或做错了什么?
下面是我的代码和带有跟踪实体的屏幕截图。
型号:
user
DBcontext:
self.request.user
应用程序服务类:
public class Case : FullAuditedAggregateRoot<Guid>
{
[Required]
public CaseType Type { get; set; }
[Required]
public string Subject { get; set; }
public string Descripion { get; set; }
//Aggregated entity
private HashSet<CaseWorkNote> _workNotes;
public IEnumerable<CaseWorkNote> WorkNotes => _workNotes?.ToList();
//
public CaseWorkNote AddNote(string text)
{
if (_workNotes is null)
{
_workNotes = new HashSet<CaseWorkNote>();
}
CaseWorkNote workNote = CaseWorkNote.Create(this, text);
_workNotes.Add(workNote);
return workNote;
}
}
public class CaseWorkNote : FullAuditedEntity
{
[ForeignKey("CaseId")]
[Required]
public Case Case { get; private set; }
[Required]
public string Text { get; set; }
private CaseWorkNote() : base() { }
public static CaseWorkNote Create(Case kase, string text)
{
return new CaseWorkNote()
{
Case = kase,
Text = text
};
}
}
谢谢
答案 0 :(得分:2)
此问题是由默认的EF Core属性访问模式和此处的ToList()
调用引起的
public IEnumerable<CaseWorkNote> WorkNotes => _workNotes?.ToList();
不确定要遵循哪种类型的方法,但是您违反了属性(尤其是集合类型)不应在每次获取中分配的简单良好设计规则。不仅因为它效率低下,而且还允许像EF Core这样的“智能”客户端将实际类型检测为List
,并尝试在loading related data时使用它来添加项目。
实际上,使用这种类型的实现,它们会添加到被丢弃的列表中,换句话说,就是无处不在。因此,与EF Core加载相关的数据/导航属性修复不起作用,这也可能会影响更改跟踪器并导致奇怪的行为。
要解决EF Core问题,应将EF Core配置为直接使用backing field。最简单的方法是在OnModelCreating
覆盖内全局设置它:
modelBuilder.UsePropertyAccessMode(PropertyAccessMode.Field);
还可以针对每个实体或每个实体属性进行设置,但是我建议以上所述,此外,EF Core 3.0的预期更改之一是Backing fields will be used by default。
无论如何,现在有问题的问题将得到解决。
不过,最好还是遵循良好做法。 _workNotes
成员应使用初始化程序或在类构造函数中进行初始化,属性getter应直接将其返回。如果这个想法是为了防止调用方通过强制转换结果来访问私有成员,那么还有其他方法可以防止不克隆集合内容的方法。例如:
//Aggregated entity
private readonly HashSet<CaseWorkNote> _workNotes = new HashSet<CaseWorkNote>();
public IEnumerable<CaseWorkNote> WorkNotes => _workNotes.Select(e => e);
//
无论是否保留导航属性的当前实现,都必须 让EF Core直接使用后备字段。
答案 1 :(得分:1)
添加外键属性mix ecto.migrate --migrations-path priv/repo/migrations
mix ecto.migrate --migrations-path other/app/priv/repo/migrations
。
还添加了CaseId
关键字。
Virtual