Save Related Data (Many to Many) in EF Core 5 without getting the actual records

Viewed 549

I am creating a web app for Lunch Reservation.

  public class Food : BaseEntity
    {
        public int FoodId { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public string Ingredients { get; set; }
        public string PhotoPath { get; set; }
        public ICollection<Menu> Menus { get; set; }
        /*public ICollection<LunchReservation> LunchReservations { get; set; } omit */ 
    }
 public class Menu : BaseEntity
    {
        public Menu()
        {
            DateCreated = DateTimeOffset.Now;
            DateModified = DateTimeOffset.Now;
        }

        public int MenuId { get; set; }

        [Column(TypeName = "date")]
        public DateTime MenuDate { get; set; }
        public bool IsPublished { get; set; }
        public ICollection<Food> Foods { get; set; }
      /*public ICollection<LunchReservation> LunchReservations { get; set; } omit */ 

    }

Everything is ok, but when I want to create a menu that can have 1 food or more I get an error.

this is my Dto for creating a Menu

  public class MenuCreationDto
    {
        public int[] FoodIds { get; set; }
        public string MenuDate { get; set; }
    }

and this code does not work for saving.

var foods = menuCDto.FoodIds.Select(f => new Food() { FoodId = f }).ToList();
Menu newMenu = new()
{
 MenuDate = menuDateInGregorian,
 Foods = foods
};

await _db.Menus.AddAsync(newMenu);
await _db.SaveChangesAsync();

but for saving foods this code is working but I don't want to get foods from the database to just make a menu.

var foods = _db.Foods.Where(f => menuCDto.FoodIds.Contains(f.FoodId)).ToList();
Menu newMenu = new()
{
 MenuDate = menuDateInGregorian,
 Foods = foods
};
await _db.Menus.AddAsync(newMenu);
await _db.SaveChangesAsync();

what can I do for saving a menu to the database without getting actual foods from the database?

1 Answers

You can use fake (a.k.a. stub) entities as in your non working example

var foods = menuCDto.FoodIds.Select(f => new Food() { FoodId = f }).ToList();

But before letting EF Core add the parent entity (Menu), you have to let it know that these are "existing" entities, otherwise it will treat them a "new" and will try to insert new Food records, rather than links as intended. You do that by attaching them to the context, which marks them as existing and unchanged:

_db.AttachRange(foods);

The rest of the code will be the same, but now should be working.

Related