为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
智慧大石 2023-05-13 16:20:16
当我保存更改时,一切看起来都很好。CaseWorkNote 实体已正确创建并添加到 workNotes 集合(案例实体的属性)。当 CurrentUnitOfWork 调用 DbContext->SaveChanges() 时,我看到我的实体在那里,状态为已添加。最后什么都没有保存到数据库中。我在我的代码中错过了什么或者我做错了什么?下面是我的代码和带有跟踪实体的屏幕截图。模型:    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            };        }    }
查看完整描述

2 回答

?
幕布斯7119047

TA贡献1794条经验 获得超8个赞

问题是默认的EF Core属性访问方式导致的,ToList()调用这里


public IEnumerable<CaseWorkNote> WorkNotes => _workNotes?.ToList();

不确定您遵循的是哪种类型的方法,但您违反了简单的良好设计规则,即属性(尤其是集合类型)不应在每次获取时分配。不仅因为它效率低下,而且还允许像 EF Core 这样的“智能”客户端检测实际类型,并在加载相关数据List时尝试使用它来添加项目。


实际上,对于这种类型的实现,他们正在添加到一个被丢弃的列表中,换句话说——无处可去。因此 EF Core 加载相关数据/导航属性修复不起作用,这也可能影响更改跟踪器并导致奇怪的行为。


要解决 EF Core 问题,您应该将 EF Core 配置为直接使用支持字段。最简单的方法是在覆盖内全局设置它OnModelCreating:


modelBuilder.UsePropertyAccessMode(PropertyAccessMode.Field);

它也可以针对每个实体或每个实体属性进行设置,但我会建议以上内容,而且 EF Core 3.0 中的预期变化之一是默认使用支持字段。


不管怎样,现在问题就解决了。


不过,最好遵循良好做法。该_workNotes成员应使用初始化程序或在类构造函数中进行初始化,属性获取器应直接返回它。如果想法是阻止调用者通过强制转换结果来访问私有成员,那么还有其他方法可以阻止不克隆集合内容的方法。例如:


//Aggregated entity

private readonly HashSet<CaseWorkNote> _workNotes = new HashSet<CaseWorkNote>();

public IEnumerable<CaseWorkNote> WorkNotes => _workNotes.Select(e => e);

//

无论是否保留导航属性的当前实现,都必须让EF Core 直接使用支持字段。


查看完整回答
反对 回复 2023-05-13
?
慕村9548890

TA贡献1884条经验 获得超4个赞

添加外键属性CaseId。还添加了Virtual关键字。


public class CaseWorkNote : FullAuditedEntity

    {

        [ForeignKey("CaseId")]

        [Required]

        public virtual Case Case { get; private set; }    

        public virtual Guid CaseId { get; private set; }  /* Added */


        [Required]

        public virtual string Text { get; set; }   


        private CaseWorkNote() : base() { }


        public static CaseWorkNote Create(Case kase, string text)

        {

            return new CaseWorkNote()

            {

                Case = kase,

                Text = text

            };

        }

    }


查看完整回答
反对 回复 2023-05-13
  • 2 回答
  • 0 关注
  • 97 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信