实体框架核心创建其他表列

时间:2019-10-19 08:42:19

标签: c# asp.net-core entity-framework-core ef-fluent-api

我正在尝试迁移一个简单的表,但是ef-core正在创建我未指定的其他列

这是我用来创建sql表的模型

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

        [Required]
        public decimal Amount { get; set; }

        [Required]
        public DateTime DateTimeCreated { get; set; } = DateTime.UtcNow;

        [MaxLength(1024)]
        public string Description { get; set; }

        [Required]
        public int CategoryId { get; set; }

        public virtual Category Category { get; set; }

        [Required]
        public int UserId { get; set; }

        public virtual User User { get; set; }
    }

EF-Core正在创建下表。

如何阻止EF-Core生成CategoryName和CategoryCashFlowId列

migrationBuilder.CreateTable(
                name: "Transactions",
                columns: table => new
                {
                    Id = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Amount = table.Column<decimal>(nullable: false),
                    DateTimeCreated = table.Column<DateTime>(nullable: false),
                    Description = table.Column<string>(maxLength: 1024, nullable: true),
                    CategoryId = table.Column<int>(nullable: false),
                    CategoryName = table.Column<string>(nullable: false),
                    CategoryCashFlowId = table.Column<int>(nullable: false),
                    UserId = table.Column<int>(nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Transactions", x => x.Id);
                    table.ForeignKey(
                        name: "FK_Transactions_Users_UserId",
                        column: x => x.UserId,
                        principalTable: "Users",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                    table.ForeignKey(
                        name: "FK_Transactions_Categories_CategoryName_CategoryCashFlowId",
                        columns: x => new { x.CategoryName, x.CategoryCashFlowId },
                        principalTable: "Categories",
                        principalColumns: new[] { "Name", "CashFlowId" },
                        onDelete: ReferentialAction.Cascade);
                });

这是我的流利的api代码

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<User>().HasIndex("Username").IsUnique();
            modelBuilder.Entity<Category>().HasKey(c => new { c.Name, c.CashFlowId });

            modelBuilder.Entity<Common.Models.CashFlow>().HasData(
                new CashFlow { Id = 1, Name = "Income" },
                new CashFlow { Id = 2, Name = "Expense" }
            );

            modelBuilder.Entity<Common.Models.Category>().HasData(
                new Category { Id = 1, Name = "Food and Drinks", CashFlowId = 2 },
                new Category { Id = 2, Name = "Travel", CashFlowId = 2 },
                new Category { Id = 3, Name = "Salary", CashFlowId = 1 }
            );
        }

编辑1:类别模型

public class Category
{
        public int Id { get; set; }

        /// <summary>
        /// <remarks> Is Indexed with CashflowId </remarks>
        /// </summary>
        [MaxLength(32)]
        [Required]
        public string Name { get; set; }

        [Required]
        public int CashFlowId { get; set; }

        public CashFlow CashFlow { get; set; }

}

编辑2:添加了CashFlow模型

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

        [MaxLength(32)]
        public string Name { get; set; }
}

编辑3:发布我的DbContext

public class AppDbContext : DbContext
    {

        public DbSet<User> Users { get; set; }

        public DbSet<Common.Models.Transaction> Transactions { get; set; }

        public DbSet<Category> Categories { get; set; }

        public DbSet<CashFlow> CashFlows { get; set; }

        public AppDbContext(DbContextOptions<AppDbContext> dbContextOptions) : base(dbContextOptions)
        {
            ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<User>().HasIndex("Username").IsUnique();
            modelBuilder.Entity<Category>().HasKey(c => new { c.Name, c.CashFlowId });

            modelBuilder.Entity<Common.Models.CashFlow>().HasData(
                new CashFlow { Id = 1, Name = "Income" },
                new CashFlow { Id = 2, Name = "Expense" }
            );

            modelBuilder.Entity<Common.Models.Category>().HasData(
                new Category { Id = 1, Name = "Food and Drinks", CashFlowId = 2 },
                new Category { Id = 2, Name = "Travel", CashFlowId = 2 },
                new Category { Id = 3, Name = "Salary", CashFlowId = 1 }
            );
        }
    }

我不明白为什么创建 CategoryName CategoryCashFlowId

请帮助

4 个答案:

答案 0 :(得分:1)

  

为什么要创建CategoryName和CategoryCashFlowId列

使用这一行:modelBuilder.Entity<Category>().HasKey(c => new { c.Name, c.CashFlowId });您正在为表Category创建一个组合键,该键不能是int

在您的Transaction对象中,您正试图为CategoryId映射键Category,如之前所述,您的复合键不能成为int的单个属性,因为组成的性质。因此,此时CategoryId不是外键,它只是另一个属性。

EF核心将用于Category对象的主复合键的两个属性放到Transaction对象中,用作外来复合键。

您可以通过删除组成来解决此问题。

答案 1 :(得分:0)

我认为这是因为您的Transaction模型具有CategoryCategoryId模型的引用(导航属性)。但是它实际上不能由Category引用CategoryId模型,因为Category模型实际上具有NameCashFlowId的复合键。因此,Entity Framework将这些添加到幕后以供参考。

我认为您可以使用CategoryCategoryId上创建一个备用键,并且将以这种方式引用它,而无需创建额外的列。

modelBuilder.Entity<Category>()
    .HasKey(c => new { c.Name, c.CashFlowId })
    .HasAlternateKey(c => c.CategoryId);

参考:https://docs.microsoft.com/en-us/ef/core/modeling/alternate-keys

答案 2 :(得分:0)

类别上的现金流应该是虚拟的。

public virtual CashFlow CashFlow { get; set; }

类别应该是

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

        /// <summary>
        /// <remarks> Is Indexed with CashflowId </remarks>
        /// </summary>
        [MaxLength(32)]
        [Required]
        public string Name { get; set; }

        [Required]
        [Index("IX_NameCashFlowId", 1, IsUnique = true)]
        public int CashFlowId { get; set; }

        [Index("IX_NameCashFlowId", 1, IsUnique = true)]
        public CashFlow CashFlow { get; set; }

}

使用此设置不需要modelBuilder.Entity<Category>().HasKey

答案 3 :(得分:0)

当您将此配置用于...

modelBuilder.Entity<Category>().HasKey(c => new { c.Name, c.CashFlowId });

类别表的主键是Name和CashFlowId,并且用于关联的交易表必须生成这些列。