CREATE UNIQUE INDEX дубликат ключа при обновлении базы данных EF Core - PullRequest
1 голос
/ 08 апреля 2020

У меня возникают проблемы с ошибкой при выполнении миграции в базу данных

Оператор CREATE UNIQUE INDEX завершен, поскольку был найден дублирующий ключ для имени объекта 'dbo.Cities' и индекса имя 'IX_Cities_CountryId'. Дубликат значения ключа (1). Оператор был прерван.

Я пишу следующий код для конфигурации контекстной таблицы и столбцов:

public class CityConfiguration : IEntityTypeConfiguration<City>
    {
        public void Configure(EntityTypeBuilder<City> builder)
        {
            builder.HasKey(x => x.Id).HasName("PK_City_Id");
            builder.Property(x => x.Id).ValueGeneratedOnAdd();

            builder.HasIndex(x => x.Name).IsUnique().HasName("IX_dbo_Cities_Name");
            builder.Property(x => x.Name).HasMaxLength(64)
                                         .IsRequired();

            builder.Property(x => x.Region).HasMaxLength(64)
                                           .IsRequired();

            builder.Property(x => x.CountryId).IsRequired();

            builder.HasOne<Country>(x => x.Country)
                   .WithOne(x => x.City)
                   .HasForeignKey<City>(x => x.CountryId);

            builder.HasData(InitDefaultCities());
        }

        private City[] InitDefaultCities()
        {
            var cities = new City[]
            {
                new City() { Id = 1, Name = "Atlanta", Region = "Georgia", CountryId = 1,   },
                new City() { Id = 2, Name = "Boston", Region = "Massachusetts", CountryId = 1 },
                new City() { Id = 3, Name = "Brooklyn", Region = "New York", CountryId = 1 },
                new City() { Id = 4, Name = "Charlotte", Region = "North Carolina", CountryId = 1 },
                new City() { Id = 5, Name = "Chicago", Region = "Illinois", CountryId = 1 },
                new City() { Id = 6, Name = "Cleveland", Region = "Ohio", CountryId = 1 },
                new City() { Id = 7, Name = "Dallas", Region = "Texas", CountryId = 1 },
                new City() { Id = 8, Name = "Denver", Region = "Colorado", CountryId = 1 },
                new City() { Id = 9, Name = "Detroit", Region = "Michigan", CountryId = 1 },
                new City() { Id = 10, Name = "San Francisco", Region = "California", CountryId = 1 },
                new City() { Id = 11, Name = "Houston", Region = "Texas", CountryId = 1 },
                new City() { Id = 12, Name = "Indianapolis", Region = "Indiana", CountryId = 1 },
                new City() { Id = 13, Name = "Los Angeles", Region = "California", CountryId = 1 },
                new City() { Id = 14, Name = "Memphis", Region = "Tennessee", CountryId = 1 },
                new City() { Id = 15, Name = "Miami", Region = "Florida", CountryId = 1 },
                new City() { Id = 16, Name = "Milwaukee", Region = "Wisconsin", CountryId = 1 },
                new City() { Id = 17, Name = "Minneapolis", Region = "Minnesota", CountryId = 1 },
                new City() { Id = 18, Name = "New Orlean", Region = "‎Louisiana", CountryId = 1 },
                new City() { Id = 19, Name = "Manhattan", Region = "New York", CountryId = 1 },
                new City() { Id = 20, Name = "Oklahoma", Region = "Oklahoma City", CountryId = 1 },
                new City() { Id = 21, Name = "Orlando", Region = "Florida", CountryId = 1 },
                new City() { Id = 22, Name = "Philadelphia", Region = "Pennsylvania", CountryId = 1 },
                new City() { Id = 23, Name = "Phoenix", Region = "Arizona", CountryId = 1 },
                new City() { Id = 24, Name = "Portland", Region = "Oregon", CountryId = 1 },
                new City() { Id = 25, Name = "Sacramento", Region = "California", CountryId = 1 },
                new City() { Id = 26, Name = "San Antonio", Region = "Texas", CountryId = 1 },
                new City() { Id = 27, Name = "Toronto", Region = "Ontario", CountryId = 2 },
                new City() { Id = 28, Name = "Salt Lake City", Region = "Utah", CountryId = 1 },
                new City() { Id = 29, Name = "Washinton D.C.", Region = "Washinton", CountryId = 1 }

            };

            return cities;
        }
    }

После добавления миграции он преобразуется в

migrationBuilder.CreateTable(
            name: "Cities",
            schema: "dbo",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1"),
                Name = table.Column<string>(maxLength: 64, nullable: false),
                Region = table.Column<string>(maxLength: 64, nullable: false),
                CountryId = table.Column<int>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_City_Id", x => x.Id);
                table.ForeignKey(
                    name: "FK_Cities_Countries_CountryId",
                    column: x => x.CountryId,
                    principalSchema: "dbo",
                    principalTable: "Countries",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Cascade);
            });

migrationBuilder.InsertData(
            schema: "dbo",
            table: "Cities",
            columns: new[] { "Id", "CountryId", "Name", "Region" },
            values: new object[,]
            {
                { 1, 1, "Atlanta", "Georgia" },
                { 28, 1, "Salt Lake City", "Utah" },
                { 26, 1, "San Antonio", "Texas" },
                { 25, 1, "Sacramento", "California" },
                { 24, 1, "Portland", "Oregon" },
                { 23, 1, "Phoenix", "Arizona" },
                { 22, 1, "Philadelphia", "Pennsylvania" },
                { 21, 1, "Orlando", "Florida" },
                { 20, 1, "Oklahoma", "Oklahoma City" },
                { 19, 1, "Manhattan", "New York" },
                { 18, 1, "New Orlean", "‎Louisiana" },
                { 17, 1, "Minneapolis", "Minnesota" },
                { 16, 1, "Milwaukee", "Wisconsin" },
                { 29, 1, "Washinton D.C.", "Washinton" },
                { 15, 1, "Miami", "Florida" },
                { 13, 1, "Los Angeles", "California" },
                { 12, 1, "Indianapolis", "Indiana" },
                { 11, 1, "Houston", "Texas" },
                { 10, 1, "San Francisco", "California" },
                { 9, 1, "Detroit", "Michigan" },
                { 8, 1, "Denver", "Colorado" },
                { 7, 1, "Dallas", "Texas" },
                { 6, 1, "Cleveland", "Ohio" },
                { 5, 1, "Chicago", "Illinois" },
                { 4, 1, "Charlotte", "North Carolina" },
                { 3, 1, "Brooklyn", "New York" },
                { 2, 1, "Boston", "Massachusetts" },
                { 14, 1, "Memphis", "Tennessee" },
                { 27, 2, "Toronto", "Ontario" }
            });

migrationBuilder.CreateIndex(
            name: "IX_Cities_CountryId",
            schema: "dbo",
            table: "Cities",
            column: "CountryId",
            unique: true);

        migrationBuilder.CreateIndex(
            name: "IX_dbo_Cities_Name",
            schema: "dbo",
            table: "Cities",
            column: "Name",
            unique: true);

Я не могу найти, где проблема, я переписываю это в SQL скрипт вручную. Однако не проблема с данными, все уникально. Если я прокомментирую уникальный индекс, он будет работать нормально. И после этого я проверю данные по скрипту из документации

    SELECT 
    Name, 
    COUNT(Name)
FROM 
    dbo.Cities
GROUP BY 
    Name
HAVING 
    COUNT(Name) > 1;

он отображает пустой результат!

Ответы [ 2 ]

1 голос
/ 08 апреля 2020

Уникальный индекс генерируется EF Core, потому что вы настроили отношение один к одному между City и Country:

builder.HasOne<Country>(x => x.Country)
       .WithOne(x => x.City)
       .HasForeignKey<City>(x => x.CountryId);

Очевидно, это не то, что требуется для данных - это должно вместо этого отношения «один ко многим» (City имеет один Country, но Country имеет много городов).

Поэтому замените свойство навигации City в Country на что-то вроде этого

public ICollection<City> Cities { get; set; }

и соответственно

builder.HasOne(x => x.Country)
   .WithMany(x => x.Cities)
   .HasForeignKey(x => x.CountryId);

И не забудьте восстановить миграцию.

1 голос
/ 08 апреля 2020

Вы создаете уникальный индекс для столбца CountryId с этим кодом:

migrationBuilder.CreateIndex(
    name: "IX_Cities_CountryId",
    schema: "dbo",
    table: "Cities",
    column: "CountryId",
    unique: true);

Поскольку он не уникален, я бы предложил установить unique в false. Опечатка может быть?

...