Добавление данных в БД из DTO

106
12 января 2021, 01:10

У меня есть класы entities для представление данных в БД и соответствующие DTO для передачи данных между слоями приложения.

    public class Dish
    {
        public int DishId { get; set; }
        [Required]
        [Index(IsUnique = true)]
        [StringLength(400)]
        public string Name { get; set; }
        public string Description { get; set; }
        public double PreparationTime { get; set; }
        public string Photo { get; set; }
        public virtual ICollection<Category> Categories { get; set; } = new List<Category>();
        public virtual ICollection<Ingredient> Ingredients { get; set; } = new List<Ingredient>();
        public virtual ICollection<IngredientAmount> IngredientAmounts { get; set; } = new List<IngredientAmount>();
        public virtual ICollection<RecipeUnit> RecipeUnits { get; set; } = new List<RecipeUnit>();
    }
public class DishDetailedDTO: IDishDTO
    {
        public int DishId { get; set; }
        [Required]
        [StringLength(400)]
        public string Name { get; set; }
        public string Description { get; set; }
        public double PreparationTime { get; set; }
        public string Photo { get; set; }
        public List<CategoryDTO> Categories { get; set; }
        public List<IngredientDetailedDTO> Ingredients { get; set; }
        public List<IngredientAmountDTO> IngredientAmounts { get; set; }
        public List<RecipeUnitDTO> RecipeUnits { get; set; }
    }
public class Category
    {
        public int CategoryId { get; set; }
        [Required]
        [Index(IsUnique = true)]
        [StringLength(20)]
        public string Name { get; set; }
        public virtual ICollection<Dish> Dishes { get; set; } = new List<Dish>();
    }
    public class CategoryDTO: ICategoryDTO
    {
        public int CategoryId { get; set; }
        [Required]
        [StringLength(20)]
        public string Name { get; set; }
    }

Проблема появляется когда я пытаюсь добавить новый обьект Dish, навигационное поле которого(например категория) уже есть в базе данных. Я получаю DishDetailedDTO из фронтенда, использую AutoMapper для получение обьекта Dish и добавляю Dish в соответствующий DbSet. Вот воспрозведение проблемы в меньшем масштабе:

        static void Main(string[] args)
        {
            Mapper.Initialize(x=> 
            {
                x.CreateMap<Dish, DishDTO>();
                x.CreateMap<Dish, DishDetailedDTO>();
                x.CreateMap<Dish, DishAvailableIngredientsDTO>();
                x.CreateMap<DishDTO, Dish>();
                x.CreateMap<DishDetailedDTO, Dish>();
                x.CreateMap<DishAvailableIngredientsDTO, Dish>();
                x.CreateMap<Category, CategoryDTO>();
                x.CreateMap<CategoryDTO, Category>();
                x.CreateMap<Ingredient, IngredientDetailedDTO>();
                x.CreateMap<Ingredient, IngredientDTO>();
                x.CreateMap<IngredientDTO, Ingredient>();
                x.CreateMap<IngredientDetailedDTO, Ingredient>();
                x.CreateMap<IngredientAmount, IngredientAmountDTO>();
                x.CreateMap<IngredientAmountDTO, IngredientAmount>();
                x.CreateMap<RecipeUnit, RecipeUnitDTO>();
                x.CreateMap<RecipeUnitDTO, RecipeUnit>();
            });
            var context = new EFDbContext();
            var dish = new DishDetailedDTO()
            {
                Name = "SomeName",
                Categories = new List<CategoryDTO>
                { 
                   new CategoryDTO()
                   {
                       Name = "Breakfast"
                   }
                }
            };
            context.Dishes.Add(Mapper.Map<Dish>(dish));
            context.SaveChanges();
            Console.ReadLine();
        }

Во время вызова SaveChanges получаю исключение

SqlException: Cannot insert duplicate key row in object 'dbo.Categories' with unique index 'IX_Name'. The duplicate key value is (Breakfast).
The statement has been terminated.
Answer 1

В типе Dish Вы декорируете свойство Name и указываете, что индекс должен быть уникальным:

[Required]
[Index(IsUnique = true)]
[StringLength(400)]
public string Name { get; set; }

Укажите, что индекс не должен быть уникальным, если индекс Вам нужен, либо полностью его уберите:

[Required]
// Раскомментируйте, если индекс необходим
// [Index(IsUnique = false)]
[StringLength(400)]
public string Name { get; set; }

Если Вы желаете добавить ссылку на уже существующую категорию, то её необходимо выбрать из БД, т.к. EF должен знать Id сущности для создания ссылки:

var cat = context.Categories.FirstOrDefault(x => x.Name.Equals("Breakfast"));
// convert cat to CategoryDTO catDto
var dish = new DishDetailedDTO() {
    Name = "SomeName",
    Categories = new List<CategoryDTO> { catDto }
};
READ ALSO
PHP. Как правильно отправить POSTFIELDS в cURL

PHP. Как правильно отправить POSTFIELDS в cURL

Мне нужно отправить данные POST через cURL как показано на картинке

112
По какому принципу работают (int) и intval?

По какому принципу работают (int) и intval?

В документации указано, что максимальное знаковое целое число для функции 9223372036854775807

116
Проблема с почтой после переезда сайта

Проблема с почтой после переезда сайта

После переезда на новый сервер перестала отправляться почта

128
Как сделать сортировку в Wordpress?

Как сделать сортировку в Wordpress?

Всем доброго времени! Либо аномалия, либо я не то делаю, есть сортировка которая работает на англверсии сайта(используется плагин WPML) но на укр

107