【问题标题】:Adding data to db that comes from DTOs将来自 DTO 的数据添加到 db
【发布时间】:2019-05-29 07:11:32
【问题描述】:

我有实体和相关的 DTO,它们用于将数据从 DB(实体框架 6)传输到我的 web api 的不同层。代码如下:

    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 对象时,问题就出现了,该对象的导航属性(比如说类别)已经存在于数据库中。一般来说,我从某个地方(前端)获取 DishDTO,然后使用 automapper 将其映射到 Dish,然后将此 Dish 添加到上下文中。以下是小规模问题的再现:

        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();

        }

那我有异常

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.

【问题讨论】:

  • 一道菜可以有多个分类?所以基本上你在菜和类别之间有一对多的关系?
  • @FakharAhmadRasul 是的
  • 您无法将所有类别的映射菜肴直接添加到数据库集中。从映射的待添加菜品中排除导航属性并添加/排除相关类别,或者将相关类别的实体状态设置为其实际状态。

标签: c# entity-framework asp.net-web-api automapper dto


【解决方案1】:

您的Dish 模型的设计是错误的,一个Dish 可以有多个Categories,而一个Category 可以有多个Dishes,这使得它是多对多关系。要处理这种情况,您需要添加另一个模型,例如:-

public class DishCategoryMapping
{
    public int Id { get; set; }
    public int DishId { get; set; }
    public int CategoryId { get; set; }

    //navigation properties
}

然后你的菜模型看起来像

public class Dish
{
    public int DishId { get; set; }
    public virtual ICollection<DishCategoryMapping> DishCategoryMappings { get; set; }

    //other properties
}

然后,您将为DishCategoryMapping 表中菜肴的每个类别插入一行。

【讨论】:

  • 对于领域模型类来说确实如此。那里的关系是多对多的。但我的 DTO 不需要在类别类中传递相关菜肴的列表
  • 查看异常,cannot insert duplicate in dbo.Categories 为什么您认为 EF 在插入新 Dish 时试图插入到 Categories 表中?这是因为当您创建 DishDTO 时,您也在初始化 List。然后,当您的自动映射器尝试将您的 DishDTO 映射到 Dish 时,它还会初始化 Dish 中的虚拟类别列表属性,这也是 EF 尝试插入类别表的原因
猜你喜欢
  • 1970-01-01
  • 2018-11-12
  • 2016-01-06
  • 2022-11-27
  • 2015-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多