Ядро фреймворка Entity создает дополнительные столбцы таблицы - PullRequest
0 голосов
/ 19 октября 2019

Я пытаюсь перенести простую таблицу, но 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 ]

1 голос
/ 19 октября 2019

почему создаются столбцы CategoryName и CategoryCashFlowId

С этой строкой: modelBuilder.Entity<Category>().HasKey(c => new { c.Name, c.CashFlowId }); Вы создаете составной ключ для таблицы Category, который не может быть int.

В вашем Transaction объекте вы пытаетесь сопоставить ключ CategoryId для вашего Category, как указано, прежде чем ваш составной ключ не может быть int ни одним свойством только по природе композиции. Таким образом, на данный момент CategoryId не является внешним ключом, это просто другое свойство.

Ядро EF помещает два свойства, которые вы использовали для первичного составного ключа вашего Category объекта, в ваш Transactionобъект, который будет использоваться в качестве внешнего составного ключа.

Вы можете решить эту проблему, удалив композицию.

0 голосов
/ 19 октября 2019

когда вы используете этот конфиг для

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

, первичным ключом таблицы категорий является Имя и CashFlowId, и таблица транзакций для отношения должна генерировать эти столбцы.

0 голосов
/ 19 октября 2019

CashFlow для категории должен быть виртуальным.

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 не требуется.

0 голосов
/ 19 октября 2019

Я полагаю, это потому, что ваша модель Transaction имеет ссылку (свойство навигации) на модель Category вместе с CategoryId. Но он не может ссылаться на модель Category по CategoryId, потому что модель Category на самом деле имеет составной ключ Name и CashFlowId. Таким образом, Entity Framework добавляет их за кулисы, чтобы ссылаться на них.

Я думаю, что вы можете создать альтернативный ключ на Category, используя CategoryId, и на него будет ссылаться таким образом, не создавая дополнительные столбцы.

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

...