使用Discriminator处理其他表,例如EF Core流利的TPT

时间:2018-07-01 05:06:39

标签: c# entity-framework database-design .net-core discriminator

我有此表,希望跟踪其他表的编辑。

namespace fais.accounting.Models.COA 
{
    public class coaEdits
    {
        public string entity_id { get; set; }
        public string editor_id { get; set; }

        [Display(Name = "Edited on")]
        public DateTime occured_on { get; set; } = DateTime.Now;

        public User editor { get; set; }
        public string entityType { get; set; }
        public string entity { get; set; } // If I coaEdits<Tkey> I can't set public Tkey entity, but it should be the object of the entityType's class right?
    }
}

我希望该表可以在外键为entity_id的地方工作。

所有其他表/类都继承了具有导航到coaEdits的类

public class coa_base
{
    [Column(Order = 2)]
    public string title { get; set; }

    [Display(Name = "Entry date")]
    public DateTime entry_date { get; set; }

    [Required]
    [Display(Name = "Last updated")]
    public DateTime updated_on { get; set; } = DateTime.Now;

    public string creator_id { get; set; } //= @TODO userManage.get_current_user <- how to default?
    public User creator { get; set; }


    public virtual List<coaEdits> edits { get; set; }

}

其中一个表的示例是

public class budgets : coa_base
{
    [Column(Order = 1)]
    [Display(Name = "Budget")]
    public string budget_id { get; set; }

    public virtual List<coa> accounts { get; set; }
}

我跑步时

dotnet ef migrations add setsUpBaseClassModelOnCOA --context ApplicationDbContext

我得到:

       migrationBuilder.CreateTable(
            name: "coaEdits",
            columns: table => new
            {
                entity_id = table.Column<string>(nullable: false),
                editor_id = table.Column<string>(nullable: false),
                occured_on = table.Column<DateTime>(nullable: false),
                editorId = table.Column<string>(nullable: true),
                entity_type = table.Column<string>(maxLength: 200, nullable: false),
                // everything below this seems like it should be wrapped up with 
                // key as entity_id and typed by entity_type, but it is not?
                entity = table.Column<string>(nullable: true), // that should be an object?  What the?
                budgetsbudget_id = table.Column<string>(nullable: true), // should be it should be the entity_id 
                coaaccount_id = table.Column<string>(nullable: true), // didto
                fundsfund_id = table.Column<string>(nullable: true), // didto
                // and so on
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_coaEdits", x => new { x.entity_id, x.editor_id, x.occured_on });
                table.ForeignKey(
                    name: "FK_coaEdits_coa_budgets_budgetsbudget_id",
                    column: x => x.budgetsbudget_id,
                    principalTable: "coa_budgets",
                    principalColumn: "budget_id",
                    onDelete: ReferentialAction.Restrict);
                table.ForeignKey(
                    name: "FK_coaEdits_coa_accounts_coaaccount_id",
                    column: x => x.coaaccount_id,
                    principalTable: "coa_accounts",
                    principalColumn: "account_id",
                    onDelete: ReferentialAction.Restrict);
                table.ForeignKey(
                    name: "FK_coaEdits_AspNetUsers_editorId",
                    column: x => x.editorId,
                    principalTable: "AspNetUsers",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
                table.ForeignKey(
                    name: "FK_coaEdits_coa_funds_fundsfund_id",
                    column: x => x.fundsfund_id,
                    principalTable: "coa_funds",
                    principalColumn: "fund_id",
                    onDelete: ReferentialAction.Restrict);
                // and so on
            });

在我期望得到的时候:

       migrationBuilder.CreateTable(
            name: "coaEdits",
            columns: table => new
            {
                entity_id = table.Column<string>(nullable: false),
                editor_id = table.Column<string>(nullable: false),
                occured_on = table.Column<DateTime>(nullable: false),
                editorId = table.Column<string>(nullable: true),
                entity_type = table.Column<string>(maxLength: 200, nullable: false),

            },
            constraints: table =>
            {
                table.PrimaryKey("PK_coaEdits", x => new { x.entity_id, x.editor_id, x.occured_on });
                table.ForeignKey(
                    name: "FK_coaEdits_coa_budgets_budgetsbudget_id",
                    column: x => x.entity_id,
                    principalTable: "coa_budgets",
                    principalColumn: "budget_id",
                    onDelete: ReferentialAction.Restrict);
                table.ForeignKey(
                    name: "FK_coaEdits_coa_accounts_coaaccount_id",
                    column: x => x.entity_id,
                    principalTable: "coa_accounts",
                    principalColumn: "account_id",
                    onDelete: ReferentialAction.Restrict);
                table.ForeignKey(
                    name: "FK_coaEdits_AspNetUsers_editorId",
                    column: x => x.editorId,
                    principalTable: "AspNetUsers",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
                table.ForeignKey(
                    name: "FK_coaEdits_coa_funds_fundsfund_id",
                    column: x => x.entity_id,
                    principalTable: "coa_funds",
                    principalColumn: "fund_id",
                    onDelete: ReferentialAction.Restrict);
                // and so on
            });

构建器上的流利选项是

builder.Entity<coaEdits>().HasKey(sc => new { sc.entity_id, sc.editor_id, sc.occured_on });
builder.Entity<coaEdits>(b =>
                           {
                               b.HasDiscriminator<string>("entityType");
                               b.Property(e => e.entityType)
                                       .HasMaxLength(200)
                                       .HasColumnName("entity_type");
                           });

builder.Entity<coa>().ToTable("coa_accounts");
builder.Entity<funds>().ToTable("coa_funds");
// and so on

纠正此问题的最佳方法是什么?有没有更好的方法?缺少的部分是

public string entity { get; set; }

我似乎无法弄清楚如何从鉴别器将其转换为类,这是我希望能够做到的。鉴别符也不必也是键,因此它也将是entity_typeentity_id的键

编辑/更新:我正在尝试将该类型应用为这样

public class coaEdits<TKey>
{
    public string entity_id { get; set; }
    public string editor_id { get; set; }

    [Display(Name = "Edited on")]
    public DateTime occured_on { get; set; } = DateTime.Now;

    public User editor { get; set; }
    public string entityType { get; set; }
    [NotMapped]
    public TKey entity { get; set; }
}

基类如下:

public class coa_base<TKey>
{
    [Column(Order = 2)]
    public string title { get; set; }

    [Display(Name = "Entry date")]
    public DateTime entry_date { get; set; }

    [Required]
    [Display(Name = "Last updated")]
    public DateTime updated_on { get; set; } = DateTime.Now;

    public string creator_id { get; set; } //= userManage.get_current_user
    public User creator { get; set; }

    public virtual List<coaEdits<TKey>> edits { get; set; }
}

示例类为

public class budgets : coa_base<budgets>
{
    [Column(Order = 1)]
    [Display(Name = "Budget")]
    public string budget_id { get; set; }

    public virtual List<coa> accounts { get; set; }

}

将其用于流利的构建器选项

builder.Entity<coaEdits<IKey>>().HasKey(sc => new { sc.entity_id, sc.editor_id, sc.occured_on });
builder.Entity<coaEdits<IKey>>(b =>
                                  {
                                      b.HasDiscriminator<string>("entityType");
                                      b.Property(e => e.entityType).HasColumnName("entity_type");
                                  });

但是我现在收到此错误

  

实体类型'coaEdits'需要定义主键。

但这是我认为的

builder.Entity<coaEdits<IKey>>().HasKey(sc => new { sc.entity_id, sc.editor_id, sc.occured_on });

如果我用所有硬编码的代码对其进行测试,则在哪里进行

builder.Entity<coaEdits<budgets>>() . . 

我得到一个要创建的coaEdits<budgets>表。

如果我尝试用builder.Entity<coaEdits<budgets>>().ToTable("coa_edits");来反击该表名,则它说另一个coaEdits<funds>coaEdits<budgets>无法共享表,因为它们不共享主键,但我认为他们entity_id

其他更新:继续使用coaEdits<TKey>方法,以便public string entity { get; set; }获得类型,我认为如果流利的api不能设置主键,那我会尝试使用属性来解决此问题,但这产生了此错误

  

实体类型'coaEdits<budgets>'具有使用数据注释定义的复合主键。要设置复合主键,请使用fluent API。

仅从此开始。

public class coaEdits<TKey>
{
    [Key]
    public string entity_id { get; set; }
    [Key]
    public string editor_id { get; set; }
    // and so on

其他信息:如果我以我认为应该正确设置表的方式更改迁移,则会遇到另一个在上下文中没有意义的错误。在这里,我将首先设置coaEdits表

        migrationBuilder.CreateTable(name: "coaEdits", columns: table => new {
            entity_id = table.Column<string>(nullable: true)
            , editor_id = table.Column<string>(nullable: true)
            , occured_on = table.Column<DateTime>(nullable: false)
            , entity_type = table.Column<string>(nullable: false)
        }, constraints: table => {
                            table.PrimaryKey("PK_coaEdits", x => x.occured_on);
                            table.ForeignKey(name: "FK_coaEdits_AspNetUsers_editorId", column: x => x.editor_id
                                             , principalTable: "AspNetUsers", principalColumn: "Id"
                                             , onDelete: ReferentialAction.Restrict);
                            table.ForeignKey(name: "FK_coaEdits_coa_budgets_entity_id", column: x => x.entity_id
                                             , principalTable: "coa_budgets", principalColumn: "budget_id"
                                             , onDelete: ReferentialAction.SetNull);
                            table.ForeignKey(name: "FK_coaEdits_coa_funds_entity_id", column: x => x.entity_id
                                             , principalTable: "coa_funds", principalColumn: "fund_id"
                                             , onDelete: ReferentialAction.SetNull);
                            // and so on
                        });

实体预算示例是这样设置的

        migrationBuilder.CreateTable(
            name: "coa_budgets",
            columns: table => new
            {
                entry_date = table.Column<DateTime>(nullable: false),
                updated_on = table.Column<DateTime>(nullable: false),
                title = table.Column<string>(nullable: true),
                creator_id = table.Column<string>(nullable: true),
                budget_id = table.Column<string>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_coa_budgets", x => x.budget_id);
                table.ForeignKey(
                    name: "FK_coa_budgets_AspNetUsers_creator_id",
                    column: x => x.creator_id,
                    principalTable: "AspNetUsers",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
            });

但是当我运行dotnet ef database update --context ApplicationDbContext时会导致此错误

  

列“ coa_budgets.budget_id”的长度或比例与引用外键“ FK_coaEdits_coa_budgets_entity_id”中的列“ coaEdits.entity_id”的长度或比例不同。参与外键关系的列必须定义为相同的长度和比例。

完整错误是:

Failed executing DbCommand (21ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE [coaEdits] (
    [entity_id] nvarchar(max) NULL,
    [editor_id] nvarchar(max) NULL,
    [occured_on] datetime2 NOT NULL,
    [entity_type] nvarchar(max) NOT NULL,
    CONSTRAINT [PK_coaEdits] PRIMARY KEY ([occured_on]),
    CONSTRAINT [FK_coaEdits_AspNetUsers_editor_id] FOREIGN KEY ([editor_id]) REFERENCES [AspNetUsers] ([Id]) ON DELETE NO ACTION,
    CONSTRAINT [FK_coaEdits_coa_budgets_entity_id] FOREIGN KEY ([entity_id]) REFERENCES [coa_budgets] ([budget_id]) ON DELETE SET NULL,
    CONSTRAINT [FK_coaEdits_coa_funds_entity_id] FOREIGN KEY ([entity_id]) REFERENCES [coa_funds] ([fund_id]) ON DELETE SET NULL,
    CONSTRAINT [FK_coaEdits_coa_objects_entity_id] FOREIGN KEY ([entity_id]) REFERENCES [coa_objects] ([object_id]) ON DELETE SET NULL,
    CONSTRAINT [FK_coaEdits_coa_programs_entity_id] FOREIGN KEY ([entity_id]) REFERENCES [coa_programs] ([program_id]) ON DELETE SET NULL,
    CONSTRAINT [FK_coaEdits_coa_projects_entity_id] FOREIGN KEY ([entity_id]) REFERENCES [coa_projects] ([project_id]) ON DELETE SET NULL,
    CONSTRAINT [FK_coaEdits_coa_accounts_entity_id] FOREIGN KEY ([entity_id]) REFERENCES [coa_accounts] ([account_id]) ON DELETE SET NULL,
    CONSTRAINT [FK_coaEdits_coa_subobjects_entity_id] FOREIGN KEY ([entity_id]) REFERENCES [coa_subobjects] ([subobject_id]) ON DELETE SET NULL,
    CONSTRAINT [FK_coaEdits_coa_subfunds_entity_id] FOREIGN KEY ([entity_id]) REFERENCES [coa_subfunds] ([subfund_id]) ON DELETE SET NULL
);
System.Data.SqlClient.SqlException (0x80131904): Column 'coa_budgets.budget_id' is not the same length or scale as referencing column 'coaEdits.entity_id' in foreign key 'FK_coaEdits_coa_budgets_entity_id'. Columns participating in a foreign key relationship must be defined with the same length and scale.

在阅读完所有内容后,我已经设置了所有匹配的外键。.entity_id是[entity_id] nvarchar(max) NULL,,预算是[budget _id] nvarchar(max) NULL,,所以我不确定SQL为什么会抛出该错误。

0 个答案:

没有答案