【问题标题】:How to have a property in a parent entity whose value belongs to a child entity two levels down with EF6 and Code-First如何使用 EF6 和 Code-First 在其值属于子实体两个级别的父实体中拥有一个属性
【发布时间】:2016-11-14 16:09:24
【问题描述】:

我需要在父实体中维护更新的属性,该属性属于下两层的子实体。我在 Asp.Net/MVC 应用程序中使用带有 Code First 和 DataAnnotations 的 EF6。

拥有这些实体:

public class Parent 
{
    [Key]
    public int IdParent {get; set;}

    // ...other properties

    //The value of this property belongs to the Child table, two levels down.    
    public int Status { get; set; }     
    public Intermediate Intermediate { get; set; }
}   


public class Intermediate
{
    [Key, ForeignKey("Parent")]
    public int IdIntermediate { get; set;}

    // ... other properties

    public Parent Parent { get; set; }
    public Child Child { get; set; }
}

public class Child 
{
   [Key, ForeignKey("Intermediate")]
   public int IdChild { get; set; }

   //...other properties

   public int Status { get; set; } // This is the property I need to keep updated in Parent Class

   public Intermediate Intermediate { get; set; } 
}

Parent 中的属性 Status 让用户快速查看在 Child 上执行的进程的结果,其中包含有关执行的详细信息。

我正在评估这些解决方案,如果您建议其中哪个更合适或其他更好的解决方案,我将不胜感激。

  • 选项 1:在数据库中创建触发器以保持更新父表中的字段。此选项将在我的实体中生成更清晰的代码,但需要为触发器创建隔离迁移,因为它必须是 SQL 命令,并且难以维护。

    public partial class AddUpdateTriggerOnChildMigration : DbMigration
    { 
    
        public override void Up()
        {
            Sql("CREATE OR REPLACE TRIGGER [Child_UpdateStatus] FOR UPDATE ON dbo.Child...");
        }
    
        public override void Down()
        {
            Sql("DROP TRIGGER [Child_UpdateStatus]");
        }
    }
    
  • 选项 2:仅将字段保留在子表中,并在父实体上计算 Status 属性。但我不知道如何让它与 DataAnnotations 或 Fluent API 一起使用。

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 
    public int Status { get; private set; }
    
  • 选项 3:将 NotMapped 设为属性 Parent.Status 并使用来自 Child 实体的代码填充它。这似乎是最糟糕的解决方案,并且也很难维护,并且当实体未附加到上下文时它将无法工作。

    public class Parent 
    {
        public int IdParent { get; set; }
    
        // ...
    
        [NotMapped]
        public int? Status 
        { 
            get
            {
                return this.Intermediate == null ? null : this.parent.Intermediate.Child.Status;
            } 
        }
    
        public Intermediate Intermediate { get; set; }
    }
    

【问题讨论】:

  • 你检查我的答案了吗?
  • 是的@user449689。我选择了选项 1,即在隔离迁移中创建的子表上的触发器。现在它起作用了,因为我的内存中没有父实体。我将在未来的版本中引入领域事件来解决内存中的实体问题。谢谢!
  • 非常感谢您的反馈,问候

标签: c# entity-framework code-first


【解决方案1】:

我给你第四个选项:覆盖SaveChanges如下:

public partial class MyDbContext : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            var changeSet = ChangeTracker.Entries<Child>();

            if (changeSet != null)
            {
                foreach (var entry in changeSet.Where(c => c.State == EntityState.Added || c.State == EntityState.Modified))
                {
                    // Update here the parent
                }
            }

            return base.SaveChanges();
        }
        catch (Exception exception)
        {

        }
    }
}

这里的想法是,当您保存上下文的更改时,您会遍历已添加或修改的所有 Child 类型的实体,然后您可以正确更新您的 ParentStatus 属性类

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 2013-10-19
    • 2014-12-03
    相关资源
    最近更新 更多