为何未使用new关键字却调用了Historique类的无参构造函数?
为什么EF查询时会调用Historique的无参构造函数?
当你通过Entity Framework执行FirstOrDefault()这类查询从数据库加载实体时,EF需要把数据库数据转化为.NET对象,这个过程叫实体物化。EF默认会调用实体类的无参构造函数创建对象实例,之后再把数据库字段值填充到对象属性中——这是ORM框架的标准行为,本身没有问题。
你的困惑大概率来自构造函数里的额外操作:你在Historique的无参构造函数中,不仅初始化了Evenements列表,还主动添加了一个默认的Evenement对象。这会导致从数据库加载的Historique对象里,除了数据库已有的事件,还多了一个新的默认事件;当你调用SaveChanges()时,EF会把这个额外对象当成需要插入的新数据,错误地保存到数据库中。
解决方案
方案1:移除构造函数中的默认事件添加
只保留列表初始化,让EF负责处理关联集合的加载:
public class Historique { [ForeignKey("Societe")] public int ID { get; set; } public Societe Societe { get; set; } public List<Evenement> Evenements { get; set; } public Historique() { // 仅初始化列表,不添加默认元素 Evenements = new List<Evenement>(); } }
如果需要在手动创建新Historique对象(而非从数据库加载)时添加默认事件,单独写一个工厂方法:
public static Historique CreateNewWithDefaultEvent() { var histo = new Historique(); histo.Evenements.Add(new Evenement()); return histo; }
后续创建新实例时,调用Historique.CreateNewWithDefaultEvent()而非直接new Historique()。
方案2:受保护构造函数+工厂方法
如果不想让外部代码直接调用无参构造函数,可以将其设为protected(EF仍能通过反射调用它加载实体),同时保留工厂方法创建带默认事件的实例:
public class Historique { [ForeignKey("Societe")] public int ID { get; set; } public Societe Societe { get; set; } public List<Evenement> Evenements { get; set; } protected Historique() { Evenements = new List<Evenement>(); } public static Historique CreateNewWithDefaultEvent() { var histo = new Historique(); histo.Evenements.Add(new Evenement()); return histo; } }
内容的提问来源于stack exchange,提问作者Floriant Fekete
相关产品推荐
相关产品推荐

