Последовательность содержит более одной ошибки элемента в EF CF Migrations

Я создал некоторые модели, добавил перенос, а затем выполнил операцию обновления базы данных, хотя при моей последней работе базы данных обновлений я получил сообщение об ошибке:

Последовательность содержит более одного элемента

Ниже вы можете найти мою конфигурацию миграции:

context.Categories.AddOrUpdate(p => p.CategoryName,
    new Category
    {
        CategoryName = "Sport"
    },
    new Category
    {
        CategoryName = "Music"
    }
);

context.Subcategories.AddOrUpdate(p => p.SubcategoryName,
    new Subcategory
    {
        SubcategoryName = "Football"
    },
    new Subcategory
    {
        SubcategoryName = "Basketball"
    },
    new Subcategory
    {
        SubcategoryName = "Piano"
    },
    new Subcategory
    {
        SubcategoryName = "Violin"
    }
);

context.Services.AddOrUpdate(p => p.ServiceType,
    new Service
    {
        ServiceType = "Football player",
        Category = { CategoryName = "Sport" },
        Subcategory = { SubcategoryName = "Football" }
    },
    new Service 
    {
        ServiceType = "Piano lessons",
        Category = { CategoryName = "Music" },
        Subcategory = { SubcategoryName = "Piano" }
    }
);

Проблема возникает при добавлении новых сервисов. У меня уже есть категории и подкатегории, и если мне нравится Category = new Category { CategoryName = "Music" }, тогда это работает, но я получаю запись Музыки дважды в моей базе данных (для этого примера). Я хочу использовать уже добавленные категории и подкатегории. Ниже также вы можете найти определения моих моделей.

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

    public string CategoryName { get; set; }
}

// Subcategory is defined the same way...

public class Service
{
    public int ServiceID { get; set; }

    public string ServiceType { get; set; }

    public virtual Category Category { get; set; }

    public virtual Subcategory Subcategory { get; set; }

}

Любая идея, как его решить?

Ответ 1

Последовательность содержит более одного элемента

Это исключение было вызвано при попытке использовать AddOrUpdate с указанием выражения идентификатора, например p => p.CategoryName. Могут быть два Categories, которые имеют одно и то же имя "Спорт" или "Музыка".

Это также может произойти в Subcategories и Services, Subcategories использует p => p.SubcategoryName и Services использует p => p.ServiceType.

Вам нужно сначала очистить дублируемую запись в базе данных. Это необходимо, так как вы хотите использовать AddOrUpdate, внутренне этот код будет использовать SingleOrDefault, и если найдено более одного элемента соответствия, будет выбрано исключение.

Ссылка на объект не установлена ​​в экземпляр объекта

Эта ошибка, вероятно, вызвана этим кодом.

Category = { CategoryName = "Sport" },
Subcategory = { SubcategoryName = "Football" }

Создание нового Service по умолчанию будет иметь значение null Category, вы не можете просто установить CategoryName.

Проблема возникает при добавлении новых служб. Я хочу использовать уже добавленные категории и подкатегории.

Categories и Subcategories должны храниться на переменных, поэтому их можно использовать Service.

var sportCategory = new Category { CategoryName = "Sport" };
var musicCategory = new Category { CategoryName = "Music" };
context.Categories.AddOrUpdate(p => p.CategoryName, 
   sportCategory, musicCategory);

var footballSub = new Subcategory { SubcategoryName = "Football" };
var basketballSub = new Subcategory { SubcategoryName = "Basketball" };
var pianoSub = new Subcategory { SubcategoryName = "Piano" };
var violinSub = new Subcategory { SubcategoryName = "Violin" };
context.Subcategories.AddOrUpdate(p => p.SubcategoryName,
   footbalSub, basketballSub , pianoSub, violinSub);

context.Services.AddOrUpdate(p => p.ServiceType,
    new Service
    {
        ServiceType = "Football player",
        Category = sportCategory,
        Subcategory = footballSub
    },
    new Service 
    {
        ServiceType = "Piano lessons",
        Category = musicCategory,
        Subcategory = pianoSub
    }
);

Но выше код все еще имеет проблемы, если служба является новой сущностью, также будет добавлена ​​существующая спортивная категория и существующая футбольная подкатегория. Вы можете прочитать эту статью для дальнейшего объяснения.

Решение

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

[ForeignKey("Category")]
public int CategoryId { get; set; }
[ForeignKey("Subcategory")]
public int SubcategoryId { get; set; }

Затем выполните миграцию.

Add-Migration AddServiceFKValues

И назначьте временный первичный ключ вручную и используйте его при определении службы. Эти временные первичные ключи не нужны при работе с существующими объектами, но может возникнуть другая проблема, если имеется более одной новой категории или подкатегории. Чтобы этого избежать, лучше использовать временные первичные ключи, после вызова AddOrUpdate, каждый первичный ключ сущности будет обновлен, если они являются существующими объектами.

var sportCategory = new Category { CategoryID = 1000, CategoryName = "Sport" };
var musicCategory = new Category { CategoryID = 1001, CategoryName = "Music" };
context.Categories.AddOrUpdate(p => p.CategoryName, 
   sportCategory, musicCategory);

var footballSub = new Subcategory { SubcategoryID = 1000, SubcategoryName = "Football" };
var basketballSub = new Subcategory { SubcategoryID = 1001, SubcategoryName = "Basketball" };
var pianoSub = new Subcategory { SubcategoryID = 1002, SubcategoryName = "Piano" };
var violinSub = new Subcategory { SubcategoryID = 1003, SubcategoryName = "Violin" };
context.Subcategories.AddOrUpdate(p => p.SubcategoryName,
   footbalSub, basketballSub , pianoSub, violinSub);

context.Services.AddOrUpdate(p => p.ServiceType,
    new Service
    {
        ServiceType = "Football player",
        CategoryID = sportCategory.CategoryID,
        SubcategoryID = footballSub.SubcategoryID
    },
    new Service 
    {
        ServiceType = "Piano lessons",
        CategoryID = musicCategory.CategoryID,
        SubcategoryID = pianoSub.SubcategoryID
    }
);

Затем обновите базу данных.

Update-Database