Entity Framework Core - внешний ключ 1 (дополнительный столбец внешнего ключа)

Я только что обновился до Entity Framework Core 2, и теперь у меня возникают проблемы с существующим дополнительным столбцом, имеющим уникальный ключ, хотя его нет в моей модели и он не определен где-либо еще.

Индекс:

migrationBuilder.CreateTable(
    name: "Vouchers",
    columns: table => new
    {
        Id = table.Column<int>(nullable: false)
            .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
        Code = table.Column<Guid>(nullable: false),
        IsClaimed = table.Column<bool>(nullable: false),
        LastModified = table.Column<DateTime>(nullable: false),
        NumberOfUnits = table.Column<int>(nullable: false),
        TransactionId = table.Column<int>(nullable: false),
        TransactionId1 = table.Column<int>(nullable: true) // why is this here?
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_Vouchers", x => x.Id);
        table.ForeignKey(
            name: "FK_Vouchers_Transactions_TransactionId1",
            column: x => x.TransactionId1,
            principalTable: "Transactions",
            principalColumn: "Id",
            onDelete: ReferentialAction.Restrict);
    });

TransactionId1 отсутствует в модели:

public class Voucher : IAutoLastModified
{
    public int Id { get; set; }
    public DateTime LastModified { get; set; }

    public int TransactionId { get; set; }
    public Transaction Transaction { get; set; }

    public int NumberOfUnits { get; set; }
    public Guid Code { get; set; }
    public bool IsClaimed { get; set; }
}

Я неправильно определяю внешний ключ?

modelBuilder.Entity<Voucher>().HasOne(x => x.Transaction).WithOne(x => x.Voucher).IsRequired(false);

Мое приложение не работает, потому что TransactionId1 всегда будет нулевым и имеет уникальное ограничение, которое я не могу удалить.

Почему EF создал дополнительный столбец для этой таблицы?

4 ответа

Это также может произойти, если вы определили свои модели с двухсторонним связыванием, но забыли использовать их свободно:

public class Customer
{
    public Guid Id { get; set; }
    public List<Order> Orders {get; set;}
}

public class Order
{
    public Guid Id { get; set; }

    public Guid CustomerId { get; set; }
    public Guid Customer { get; set; }
}

// AppDbContext
builder.Entity<Order>()
     .HasOne(x => x.Customer)
     .WithMany() //WRONG -> should be .WithMany(x => x.Orders) OR modify the model to not define the collection at the customer entity
     .HasForeignKey(x => x.CustomerId)
     .OnDelete(DeleteBehavior.SetNull)
;

Итак, я выяснил, в чем проблема (оставив вопрос здесь для любого, кто совершит ту же ошибку, что и я).

Я пометил отношения как Необязательные, но столбец был int вместо int? поэтому EF решил добавить свою собственную колонку за кулисы.

После исправления этой ошибки мне пришлось заново создать базу данных - миграция не прошла успешно из-за существующих данных.

У меня была эта проблема, когда тип поля внешнего ключа в дочернем элементе не соответствовал типу поля первичного ключа в родительском.

Пример:

public class User // Parent
{
    public long Id { get; set; }
    public virtual ICollection<UserLike> UserLikes { get; set; } // Child collection
}

public class UserLike // Child
{
    public int Id { get; set; }
    public int UserId { get; set; } // Foreign key
    public virtual User User { get; set; } // Navigation property
}

В DbContext у меня было:

modelBuilder.Entity<UserLike>(entity =>
{
    entity.HasOne(x => x.User)
    .WithMany(x => x.UserLikes)
    .OnDelete(DeleteBehavior.ClientCascade);
}

Вот, int UserId не соответствует типу первичного ключа long Idв родительском. Решение состоит в том, чтобы сделатьUserId long:

public class UserLike // Child
{
    public int Id { get; set; }
    public long UserId { get; set; } // Foreign key
    public virtual User User { get; set; } // Navigation property
}

У меня возникла та же проблема, и для меня было решено добавить тег DataAnnotation [ForeignKey("")] над свойством навигации, чтобы явно указать, какой из них использовать.

public Guid TransactionId { get; set; }

[ForeignKey("TransactionId ")]
public Transaction Transaction { get; set; }

Спасибо

Я сталкивался с этой проблемой в прошлом при использовании подхода Data first. Мне пришлось удалить существующий столбец, но после каждого обновления этот столбец появляется в структуре схемы edmx, которую мне пришлось вручную удалить, чтобы он работал. Вы можете воссоздать EDMX вместо обновления.

Вы должны указать строителю модели, какой столбец в вашем voucher таблица, которую вы хотите использовать в качестве столбца внешнего ключа. В противном случае Entity Framework просто создаст его для вас.

Для этого добавьте HasForeignKey метод беглой установки:

modelBuilder.Entity<Voucher>().HasOne(x => x.Transaction).WithOne(x => x.Voucher).HasForeignKey<Voucher>(x => x.TransactionId).IsRequired(false);

Обратите внимание, что при настройке отношения "один к одному" необходимо определить сущность, в которой существует внешний ключ, в качестве общего ограничения.

Другие вопросы по тегам