3.3 创建模型 阴影属性

概念

影子属性是未在 .NET 实体类中定义但在 EF Core 模型中为该实体类型定义的属性。 这些属性的值和状态纯粹在更改跟踪器中进行维护。 当数据库中的数据不应在映射的实体类型上公开时,阴影属性非常有用。

2020-07-22_081734

阴影属性不属于您的实体类,因此,您无法在访问实体的其它属性时访问它,只能在构建实体数据模型时为实体类型配置阴影属性,并且他们也将映射到数据库列,阴影属性的值和状态仅在更改追踪器中维护;

让我们了解shadow属性的实际方面。假设我们需要维护数据库表中每个记录的创建和更新日期。您学习了如何通过在实体类中定义CreatedDate和UpdatedDate属性来设置EF Core中实体的创建和修改日期。在这里,我们将看到如何通过使用阴影属性而不在实体类中包含阴影属性来实现相同的结果。

考虑以下学生实体类。

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
}

上面的Student类不包含CreatedDate和UpdatedDate属性来维护创建或更新的时间。我们将它们配置为Student实体上的阴影属性。

1.定义影子属性

public class SchoolContext : DbContext
{
    public SchoolContext() : base()
    {

    }

    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        modelBuilder.Entity<Student>().Property<DateTime>("CreatedDate");
        modelBuilder.Entity<Student>().Property<DateTime>("UpdatedDate");
    }

    public DbSet<Student> Students { get; set; }
}

如您所见,Property()方法用于配置阴影属性。将shadow属性的名称指定为字符串,并将类型指定为通用参数。如果在Property()方法中指定的名称与现有属性的名称匹配,则EF Core将将该现有属性配置为阴影属性,而不是引入新的阴影属性。

2. 数据库中的阴影属性

定义阴影属性后,我们需要更新数据库架构,因为阴影属性将映射到相应的数据库列。
为此,请在Visual Studio的程序包管理器控制台中使用以下命令添加数据库迁移。

PM> add-migration addShadowProperty
PM> update-database

现在,Student表将包括两列,SQL Server中的CreatedDate和UpdatedDate,如下所示。
因此,即使我们没有在Student类中包含这些属性并将其配置为阴影属性,数据库也将具有相应的列。

3.访问阴影属性

using (var context = new SchoolContext())
{
    var std = new Student(){ StudentName = "Bill"  };

    // sets the value to the shadow property
    context.Entry(std).Property("CreatedDate").CurrentValue = DateTime.Now;

    // gets the value of the shadow property
    var createdDate = context.Entry(std).Property("CreatedDate").CurrentValue;
}

但是,在我们的方案中,我们想在SaveChanges()方法上自动将值设置为这些阴影属性,这样就不必在每个实体对象上手动设置它们。因此,请在上下文类中重写SaveChanges()方法,如下所示。

public override int SaveChanges()
{
    var entries = ChangeTracker
        .Entries()
        .Where(e =>
                e.State == EntityState.Added
                || e.State == EntityState.Modified);

    foreach (var entityEntry in entries)
    {
        entityEntry.Property("UpdatedDate").CurrentValue = DateTime.Now;

        if (entityEntry.State == EntityState.Added)
        {
            entityEntry.Property("CreatedDate").CurrentValue = DateTime.Now;
        }
    }

    return base.SaveChanges();
}

这将自动将值设置为CreatedDate和UpdatedDate阴影属性。
现在,执行以下代码并检查数据库中的记录。

using (var context = new SchoolContext())
{
    var std = new Student(){ StudentName = "Bill"  };
    context.Add(std);
    context.SaveChanges();
}

上面的代码将在Student表中插入带有CreatedDate和UpdatedDate的以下记录。

因此,通过配置阴影属性,我们不必将它们包括在实体类中。

在所有实体上配置阴影属性

您可以一次在所有实体上配置阴影属性,而不是为所有实体手动配置它们。
例如,我们可以一次在所有实体上配置CreatedDate和UpdatedDate,如下所示。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var allEntities = modelBuilder.Model.GetEntityTypes();

    foreach (var entity in allEntities)
    {
        entity.AddProperty("CreatedDate",typeof(DateTime));
        entity.AddProperty("UpdatedDate",typeof(DateTime));
    }
}

何时使用阴影属性

阴影属性可以在两种情况下使用:

  1. 当您不想在映射的实体上公开数据库列时,例如上面讨论的方案。
  2. 当您不想公开外键属性而只想使用导航属性来管理关系时。外键属性将是shadow属性并映射到数据库列,但不会作为实体的属性公开。 (在EF Core中,如果您未在实体类中定义外键属性,则它将自动为此生成阴影属性。您无需手动配置外键属性。)

了解如何在运行时检查阴影属性

https://www.entityframeworktutorial.net/faq/how-to-check-shadow-property-at-runtime.aspx

应用

  • 审计功能
    目前为止审计 怎么跟用户关联的没有看到;那几个审计字段是知道的;
  • 维护数据库表中每个记录的创建和更新日期
posted @ 2020-07-22 14:23  maanshancss  阅读(281)  评论(0编辑  收藏  举报