You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何未使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 16:00:27