I have 3 tables in my database: Ingredient, IngredientRecipe and Recipe. Adding data to Ingredient works correctly. IngredientRecipe is for making relation between Ingredient and Recipe. When I want to add a Recipe to database, nothing happens. No errors, no data in the database.
My error message:
System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 64. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles.
DbContext class:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<Ingredient> IngredientsTable { get; set; }
public DbSet<IngredientRecipe> IngredientRecipesTable { get; set; }
public DbSet<Recipe> RecipesTable { get; set; }
}
Ingredient, IngredientRecipe and Recipe:
public class Ingredient : BaseEntity
{
public string Name { get; set; }
public int Kcal { get; set; }
public virtual ICollection<IngredientRecipe> IngredientRecipe { get; set; }
}
public class IngredientRecipe : BaseEntity
{
public int IngredientId { get; set; }
public int RecipeId { get; set; }
public int Amount { get; set; }
public Ingredient Ingredient { get; set; }
public Recipe Recipe { get; set; }
}
public class Recipe : BaseEntity
{
public string Name { get; set; }
public List<IngredientRecipe> ListOfIngredients { get; set; }
}
And here is my form code:
@page "/recipes/create"
@inject IIngredientRepository ingredientRepository
@inject IRecipeRepository recipeRepository
@inject NavigationManager navManager
<div class="container col-12">
<EditForm Model="Recipe" OnValidSubmit="SaveRecipe">
<button class="btn btn-primary">Save recipe</button>
<div class="col-4">
<div class="form-control">
<InputText @bind-Value="Recipe.Name" />
</div>
</div>
</EditForm>
</div>
<div class="row">
<div class="col-6">
<TableTemplate Items="ListOfIngredients">
<TableHeader>
<th>Name</th>
<th>Kcal</th>
<th>Action</th>
</TableHeader>
<RowTemplate Context="ingredient">
<td>@ingredient.Name</td>
<td>@ingredient.Kcal</td>
<td>
<button class="btn btn-primary" @onclick="@(()=>SetTheAmount(ingredient))">Add</button>
</td>
</RowTemplate>
</TableTemplate>
</div>
<div class="col-6">
List of ingredients
<br />
@if (ListOfIngredientAmounts.Any())
{
<TableTemplate Items="ListOfIngredientAmounts">
<TableHeader>
<th>Name</th>
<th>Amount</th>
<th>Action</th>
</TableHeader>
<RowTemplate Context="ingredient">
<td>@ingredient.Ingredient.Name</td>
<td>@ingredient.Amount</td>
<td>
<button class="btn btn-primary">Delete</button>
</td>
</RowTemplate>
</TableTemplate>
}
</div>
</div>
@if (IngredientAmount.Ingredient != null)
{
<p>Ingredient Id: @IngredientAmount.IngredientId | Name: @IngredientAmount.Ingredient.Name | Amount: @IngredientAmount.Amount</p>
<EditForm Model="IngredientAmount" OnValidSubmit="AddIngredientToIngredientAmountList">
<div class="form-group">
Value
<InputNumber @bind-Value="IngredientAmount.Amount" />
</div>
<button class="btn btn-primary" type="submit">Add to list</button>
</EditForm>
}
@code{
public Recipe Recipe { get; set; } = new Recipe();
public List<Ingredient> ListOfIngredients { get; set; } = new List<Ingredient>();
public IngredientRecipe IngredientAmount { get; set; } = new IngredientRecipe();
public List<IngredientRecipe> ListOfIngredientAmounts { get; set; } = new List<IngredientRecipe>();
protected override async Task OnInitializedAsync()
{
ListOfIngredients = await ingredientRepository.GetListOfIngredients();
}
private void SetTheAmount(Ingredient ingredient)
{
IngredientAmount = new IngredientRecipe();
IngredientAmount.IngredientId = ingredient.Id;
IngredientAmount.Recipe = Recipe;
IngredientAmount.RecipeId = Recipe.Id;
IngredientAmount.Ingredient = ingredient;
}
private void AddIngredientToIngredientAmountList()
{
ListOfIngredientAmounts.Add(IngredientAmount);
IngredientAmount = new IngredientRecipe();
}
private async void SaveRecipe()
{
if (ListOfIngredientAmounts.Any())
{
Recipe.ListOfIngredients = ListOfIngredientAmounts;
await recipeRepository.CreateRecipe(Recipe);
ListOfIngredientAmounts = new List<IngredientRecipe>();
Recipe = new Recipe();
navManager.NavigateTo("/recipes");
}
}
}
And my repository and controller responsible for post:
public async Task CreateRecipe(Recipe recipe)
{
var response = await httpClient.PostAsJsonAsync(url, recipe);
if (!response.IsSuccessStatusCode)
{
throw new ApplicationException(await response.Content.ReadAsStringAsync());
}
}
[HttpPost]
public async Task<ActionResult<int>> Post(Recipe recipe)
{
context.RecipesTable.Add(recipe);
await context.SaveChangesAsync();
return recipe.Id;
}
And here is link to GitHub https://github.com/szymonJag/CookBook
SaveChangesAsync()so how do you know there aren't any errors?try { await context.SaveChangesAsync(); } catch(Exception e) { Console.WriteLine($"{e} exception");}SaveChangesAsync()try { await context.SaveChangesAsync(); } catch(DbUpdateConcurrencyException) { throw; }Please correct me if it is possible