数据库的每个表中的多个公共字段CreatedOn和CreatedBy。如何不重复每一张桌子

时间:2017-09-22 15:05:37

标签: entity-framework inheritance asp.net-core-mvc

之情况:

<button type="button">

问题是,每次创建表时我都要重复添加这两列。

但我想这样 -

<form>

但是在为部门或患者创建行时,它的创建问题[显示与其他表的外键冲突错误]。

在EF核心中,有每个层次结构表(TPH),但在这种情况下,每个表将合并到一个表中。但这并没有给我任何解决方案。

期待专家的建议......

1 个答案:

答案 0 :(得分:3)

底线是:使用EntryLog作为基本类型,不要告诉EF它。保持EF-core不遗漏基类型很容易:只注册派生类型。这样做,EF-core会将您的子类型映射到他们自己的表中,就好像它们没有共同类型一样。

现在EntryLog将不再需要Id,它应该是抽象的:

public abstract class EntryLog
{
    public DateTime CreatedOnUtc { get; set; }
    public string CreatedBy { get; set; }
}

这是否足够取决于您的具体要求。有几种可能性。

1。没有其他配置

如果您对默认约定感到满意,EF将适用于​​公共属性,您已完成。 CreatedOnUtc将映射到DateTime2列(在Sql Server中)和CreatedBynvarchar(max)实体的每个表中的EntryLog列。

但是,如果您确实需要自定义配置 - 例如,如果您想将CreatedBy映射到nvarchar(50)列,则应该应用其他映射说明。当然,您仍然只想对公共属性进行一次映射 - 如果 映射TPH方案中的基类型,也会发生这种情况。怎么做?

2。基类型

中的数据注释

最简单的选择是添加数据注释:

public abstract class EntryLog
{
    public DateTime CreatedOnUtc { get; set; }

    [MaxLength(50)]
    public string CreatedBy { get; set; }
}

就是这样。

但是有些开发团队不想使用数据注释来映射指令。此外,EF的流畅映射提供了比数据注释更多的选项。如果数据注释因任何原因而无法满足要求,则必须应用流畅的配置。但是,您仍然只想配置一次公共属性。实现这一目标的可行方法是为每个EntryLog使用IEntityTypeConfiguration,并让每个具体配置派生自基类。这提供了两个选项。

3。基类包含常规属性

选项4将清楚说明为什么我在这里谈论“常规属性”。这就是它的样子:

abstract class EntryLogConfiguration
{
    public void ConfigureBase<TEntity>(EntityTypeBuilder<TEntity> builder)
        where TEntity : EntryLog
    {
        // Just an example of how to configure a base property.
        builder.Property(e => e.CreatedBy).HasMaxLength(50);
    }
}

class DepartmentConfiguration : EntryLogConfiguration, 
    IEntityTypeConfiguration<Department>
{
    public void Configure(EntityTypeBuilder<Department> builder)
    {
        builder.Property(p => p.DepartmentName).HasMaxLength(100);
        ConfigureBase(builder);
    }
}

在上下文中:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.ApplyConfiguration(new DepartmentConfiguration());
}

4。使用阴影属性

Shadow properties是EF-core的新功能。

  

影子属性是未在.NET实体类中定义但在EF Core模型中为该实体类型定义的属性。这些属性的值和状态完全保留在Change Tracker中。

假设您希望将CreatedBy作为类属性(因为您希望在UI中显示它),但只需要CreatedOnUtc作为在后台设置的属性,而不应该暴露。现在EntryLog将如下所示:

public abstract class EntryLog
{
    public string CreatedBy { get; set; }
}

所以属性CreatedOnUtc消失了。它已作为shadow属性移动到基本配置:

abstract class EntryLogConfiguration
{
    public void ConfigureBase<TEntity>(EntityTypeBuilder<TEntity> builder)
        where TEntity : EntryLog
    {
        builder.Property(e => e.CreatedBy).HasMaxLength(50);
        builder.Property<DateTime>("CreatedOnUtc");
    }
}

现在,您无法直接设置CreatedOnUtc,只能通过EF的更改跟踪器。最好的地方是在上下文中覆盖SaveChanges

    public override int SaveChanges()
    {
        foreach (var entry in ChangeTracker.Entries<EntryLog>())
        {
            entry.Property<DateTime>("UpdatedOnUtc").CurrentValue = DateTime.UtcNow;
        }
        return base.SaveChanges();
    }

当然,如果UpdatedOnUtc是常规属性,这个覆盖也会派上用场,但你可以这样做

            entry.Entity.CreatedOnUtc = DateTime.UtcNow;

我希望这会给你足够的思考,以找出最适合你的选择。