添加到聚合根目录时未保存子实体

时间:2019-06-28 11:04:26

标签: c# entity-framework-core aspnetboilerplate

当我保存更改时,一切看起来都很好。正确创建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
            };
        }
    }

谢谢

debugger - you can see the entity is there.

2 个答案:

答案 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