在无参数构造函数(实体框架)中的初始化

本文关键字:初始化 框架 实体 参数 构造函数 | 更新日期: 2023-09-27 18:13:16

我的问题是:

  1. 是否有可能在EF的无参数构造函数中初始化依赖对象?
  2. 如果是,正确的方法是什么?如果没有,如果不是在构造函数中,依赖对象应该在哪里初始化?

在测试我的代码时,似乎我不能在无参数构造函数中初始化对象;如果我这样做,实体框架将无法正确加载它们。

加载对象时,这段代码正确加载

abstract public class Channel
{
    public long ID { get; protected set; }
    public Verification Verification { get; protected set; }
    public Channel() { }
}

然而这段代码不能正确加载

abstract public class Channel
{
    public long ID { get; protected set; }
    public Verification Verification { get; protected set; }
    public Channel()
    {
        Verification = new Verification();
    }
}

注意:在上面的例子中,我是从已经存储在数据库中的数据中工作的,我没有重新创建数据,然后为每个例子加载它(我不知道它有任何区别)。

是具体的派生类:

public class Email : Channel
{
    public string Address { get; protected set; }
    public Email(string address)
    {
        Address = address;
    }
    public Email() : this(string.Empty) { }
}

澄清一下,我是这样创建、保存和加载我的实体的:

// Creating / saving
using (Context context = new Context())
{
    Email email = new Email("person@blah.com");
    // Do some stuff with the Verification object
    context.Channels.Add(email);
    context.SaveChanges(); // EF assigns an ID of 1
}
// Loading
using (Context context = new Context())
{
    Email email = context.Find(1); // Using the value of 1 from above
}

当使用上面的"正确加载"构造函数加载时,验证对象被正确加载-它是我创建/保存的对象。当使用"不正确加载"构造函数时(具有一些初始化的构造函数),验证对象只是一个"新"版本(没有ID为0的代理)。

除了一页,我看到的每一页都说对象初始化在无参数构造函数中是好的,因为EF会正确地将它们识别为未修改的,尽管初始化,并用从数据库中提取的值覆盖它们。虽然我没有看到任何关于如何在无参数构造函数中初始化对象的建议,但我看到的唯一一个说不能这样做的页面是在这里。

我希望有无参数的构造函数,当它们被保证时,而不需要创建一个无用的参数化构造函数来绕过EF的内部工作。这种"简单"简直要了我的命。我越深入EF,任何面向对象的代码就越会在我眼前恶化。= * (

在无参数构造函数(实体框架)中的初始化

正如我在回答中提到的,在实体框架类模型中,与真正的领域模型相反,在实体的构造函数中初始化引用导航属性是不好的做法。

但是的…我们必须在的某个地方初始化引用导航属性。那么哪个地方最好呢?我认为这个信息是:保持简单。我认为应该有可能破解EF,用它自己实现的对象替换默认对象,但这并不是微不足道的。这可能是一个意想不到的bug的来源。

基本上有两个选项:

  • 不要初始化它们,设置原始外键属性:

    var channel = new Channel { VerificationId = someId };
    

    这可能更伤域驱动的老手的眼睛,但是使用外键关联(引用和原始属性的组合)是EF官方推荐的,因为它有很多优点。

一个EF类模型只是远程类似于一个领域驱动的模型。许多DDD原则不能应用于它,因为EF模型"只是"一个数据访问层。与其与之抗争,不如接受这一点。