为Entity Framework导航属性设置默认对象

3

如何为实体设置默认对象?

假设我有一个Person实体,最初没有Profile要求。

现在我需要一个Profile,但是已经存在的实体目前没有Profile。

有没有办法在将来加载这些实体时为它们提供默认对象,以便使用Person实体的任何人都可以假定Profile永远不为空并且总是有一个值-即使它是默认值。

下面您可以看到我尝试过什么 - 它确实创建了一个默认值 - 但即使数据库中有内容,它始终返回默认对象。

  • 如果Profile为null,则希望返回一个默认初始化的对象
  • 如果Profile不为null,则希望返回来自数据库的对象

另外,将“默认”对象附加到我的dbcontext的最明智方法是什么?

如何实现这种期望的行为?

public class Person
{
    [Key]
    public int Id {get; set;}

    private Profile _profile;
    public virtual Profile Profile
    {
        get
        {
            return _profile ?? (_profile= new Profile
            {
                Person = this,
                PersonId = Id
            });
        }
        set
        {
            _profile = value;
        }

        // properties
    }
}

public class Profile
{
    [Key, ForeignKey("Person")]
    public int PersonId {get; set;}

    [ForeignKey("PersonId")]
    public virtual Person Person{ get; set; }

    // properties
}

我知道你可以初始化集合使它们不为null,但我也想初始化单个对象。


当您加载一个在数据库中没有资料的Person对象,然后更新其某个属性并将其保存回数据库时,您希望发生什么?EF是否应该为这样的人创建一个资料档案? - Yacoub Massad
这个 User 类是什么?它是 Person 的基类吗? - Yacoub Massad
@YacoubMassad 抱歉 - 我调整了我的实际代码以使问题更容易理解,但我忘记将 User 类重命名为 Person - 实际上它应该是一个 Person - 我已编辑我的问题以反映这一点。 - Alex
这听起来是一件非常奇怪的事情。你的使用场景是什么? - undefined
我认为你在尝试这样做时是在玩火... 在我看来,保持你的实体简单对象(POCO),并将任何逻辑处理放在业务逻辑层(BL)中。 - undefined
显示剩余6条评论
1个回答

3
使用 ObjectContext.ObjectMaterialized 事件
每当一个实体在被加载后,都会引发此事件。
在上下文的构造函数中订阅此事件。在事件处理程序中,检查实体类型是否为“Person”,如果是,则为该人员创建新配置文件。以下是代码示例:
public class Context : DbContext
{
    private readonly ObjectContext m_ObjectContext;

    public DbSet<Person> People { get; set; }
    public DbSet<Profile> Profiles { get; set; }

    public Context()
    {
        var m_ObjectContext = ((IObjectContextAdapter)this).ObjectContext;

        m_ObjectContext.ObjectMaterialized += context_ObjectMaterialized;

    }

    void context_ObjectMaterialized(object sender, System.Data.Entity.Core.Objects.ObjectMaterializedEventArgs e)
    {

        var person = e.Entity as Person;

        if (person == null)
            return;

        if (person.Profile == null)
            person.Profile = new Profile() {Person = person};

    }
}

请注意,如果您提交更改,新的配置文件将保存回数据库。

这很不错。我能够利用它使Kendo Grid在非扁平化视图模型上运行,这使我能够保持性能(而不是在内存中进行过滤和排序)。总的来说,这样做有什么缺点吗? - Charles
当测试Profile不为空的情况时,我收到了“已经有一个与此命令关联的打开的DataReader”的错误提示。 - Sebastian Patten

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接