Случай:
Пользователь может добавить еду, и это name, description, image и ingredients. Пользователь отправляет такую полезную нагрузку
{
"ingredients":[
{
"id":1,
"name":"Gooseberry",
"kcal":41,
"proteins":0.8,
"fat":0.2,
"carbohydrates":11.8,
"type":null,
"quantity":100
}
],
"title": "title",
"image": null,
"description":"\"<p>sdf</p>\"",
"type":"breakfast"
}
Webapi потребляет полезную нагрузку и для Meal сохраняет данные в контексте БД, берет ingredients список и просматривает каждый элемент в foreach и добавляет mealId уникальный номер, чтобы были ссылки на ингредиенты для конкретного блюда.
Meal сущность:
public class Meal
{
public int Id { get; set; }
public string Uuid { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string Author { get; set; }
public DateTime? Created { get; set; }
public string Type { get; set; }
public virtual List<MealIngredientsList> Ingredients { get; set; }
}
MealIngredientsList сущность:
public class MealIngredientsList
{
public int Id { get; set; }
public double Carbohydrates { get; set; }
public double Fat { get; set; }
public double Kcal { get; set; }
public string Name { get; set; }
public double Proteins { get; set; }
public double Quantity { get; set; }
public string Type { get; set; }
public string MealId { get; set; }
[ForeignKey("Uuid")]
public virtual Meal Meal { get; set; }
}
MealDto объект передачи данных:
public class MealDto
{
public string Uuid { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string Author { get; set; }
public DateTime? Created { get; set; }
public string Type { get; set; }
public List<MealIngredientsListDto> Ingredients { get; set; }
}
и MealIngredientsListDto:
public class MealIngredientsListDto
{
public double Carbohydrates { get; set; }
public double Fat { get; set; }
public double Kcal { get; set; }
public string Name { get; set; }
public double Proteins { get; set; }
public double Quantity { get; set; }
public string Type { get; set; }
public string MealId { get; set; }
}
Итак, как я уже сказал, meal и ingredients правильно сохраняются в БД. У каждого ингредиента есть ссылка MealId на Meal, но я пытаюсь отобразить, чтобы ответ для еды содержал массив ingredients с ингредиентами, которые назначены для конкретного блюда.
Прямо сейчас ответ выглядит так, а ingredients — это пустой массив:
{
"status": 200,
"list": {
"uuid": "e7206453",
"title": "\"<p>sdf</p>\"",
"description": "\"<p>sdf</p>\"",
"image": null,
"author": "982eb82e",
"created": "2023-04-03T23:19:20.8039742+02:00",
"type": "breakfast",
"ingredients": []
}
}
Мне удалось сопоставить пользовательские настройки, так что это не массив объектов ob, а объект со свойствами, и я сделал это с помощью
CreateMap<UserProfileDto, UserSettingDto>()
.ForMember(m => m.newsletterConsent, m => m.MapFrom(s => s.Settings))
.ForMember(m => m.messageEmailNotification, m => m.MapFrom(s => s.Settings));
и используя .Include(u => u.Settings) на основе его DTO, и он отлично работает
но я понятия не имею, как сопоставить это, чтобы получить ингредиенты в массив.
Пробовал с _context.Meals.Where(x => x.Uuid == newUuid).Include(x => x.Ingredients).OrderByDescending(x => x.Created).ToList();, но не смог использовать профиль сопоставления для достижения этой цели.
У кого-нибудь есть решение/подсказка для этого?
Сохраняется правильно. Он содержит правильный MealId как ссылку на Meal.
убедитесь, что у вас есть сопоставление между MealIngredientsList и MealIngredientsListDto
Почему между MealIngredientsList и MealIngredientsListDto? Meal и MealDto должны хранить MealIngredientsList в виде массива?
Automapper с этим справится за вас (вам также понадобится сопоставление между Meal и MealDto) docs.automapper.org/en/stable/…
Что ж, именно поэтому я здесь - потому что понятия не имею, как к этому подступиться. ;)
Проверьте это также, надеюсь, это поможет docs.automapper.org/en/stable/Nested-mappings.html
Я видел это раньше, но это не звонит в колокол. Но все равно спасибо.





Рабочее решение (без сопоставления с DTO):
public class Meal
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] <-- mapping by MealId will cause not incrementing Id - use this
public int Id { get; set; }
public string MealId { get; set; }
public string Title { get; set; }
[NotMapped]
public IEnumerable<MealIngredientsList> IngredientsList { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string Author { get; set; }
public DateTime? Created { get; set; }
public string Type { get; set; }
public virtual ICollection<MealIngredientsList> Ingredients { get; set;
}
}
public class MealIngredientsList
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public double Carbohydrates { get; set; }
public double Fat { get; set; }
public double Kcal { get; set; }
public string Name { get; set; }
public double Proteins { get; set; }
public double Quantity { get; set; }
public string Type { get; set; }
[ForeignKey("Meal")] <- created foreign key MealId and model builder change default key for reference (by default is Id)
public string MealId { get; }
[JsonIgnore] <-- to avoid infinite loop 'cause This error is caused by the circular reference between the Meal and MealIngredientsList entities. When you serialize the Meal entity to JSON, it also includes the related MealIngredientsList entities, which in turn reference the parent Meal entity, causing an infinite loop.
public virtual Meal Meal { get; set; }
}
Контекст БД для ссылки по определенному ключу (по умолчанию не по идентификатору)
modelBuilder.Entity<Meal>()
.HasKey(m => m.MealId);
modelBuilder.Entity<MealIngredientsList>()
.HasKey(mil => new { mil.Id, mil.MealId });
modelBuilder.Entity<MealIngredientsList>()
.HasOne(mil => mil.Meal)
.WithMany(m => m.Ingredients)
.HasForeignKey(mil => mil.MealId);
Услуга:
var newMeal = new Meal
{
MealId = newUuid,
Title = dto.Title,
Description = dto.Description,
Image = dto.Image,
Author = user,
Created = DateTime.Now.ToLocalTime(),
Type = dto.Type,
Ingredients = new List<MealIngredientsList>(), <- include reference to ingredients
};
foreach(var item in dto.IngredientsList)
{
var ingredients = new MealIngredientsList
{
Name = item.Name,
Carbohydrates = item.Carbohydrates,
Kcal = item.Kcal,
Proteins = item.Proteins,
Quantity = item.Quantity,
Type = item.Type,
Meal = newMeal, <-- assign reference for created Meal entity
};
newMeal.Ingredients.Add(ingredients);
}
и в конце принимать все блюда с его ингредиентами
_context.Meals.Include(m => m.Ingredients).ToList();
и это работает.
Вы можете проверить, правильно ли сохранен MealIngredientsList в БД?