Search code examples
xamarin.formscascading-deletessqlite-net-extensions

Delete Cascade not working


I have two tables in my database, one for recipes and one for their ingredients. When a particular recipe is deleted, I want all its ingredients gone as well. I have declared a one to many relationship with cascade attribute set but when I delete some recipe it does not delete the relevant ingredients.

Here are my tables:

    public class Recipe_Model
    {

        [PrimaryKey AutoIncrement]
        public int RecipeID { get; set; }
        public string RecipeName { get; set; }
        public double RecipeCost { get; set; }
        public double ServingsNo { get; set; }
        public double CostPercent { get; set; }
        public double SellingPrice { get; set; }
        public double CostPerServing { get; set; }

        [OneToMany(CascadeOperations = CascadeOperation.All)]      // One to many relationship with Ingredients
        public ObservableCollection<Ingredients_Model> Ingredients { get; set; }
    }

    public class Ingredients_Model
    {
        [PrimaryKey AutoIncrement]
        public int IngredientID { get; set; }

        [ForeignKey(typeof(Recipe_Model))]
        public int RecipeID { get; set; }

        public string IngredientName { get; set; }
        public string UsedUnit { get; set; }
        public string PurchasedUnit { get; set; }
        public double QuantityUsed { get; set; }
        public double QuantityPurchased { get; set; }
        public double PurchasePrice { get; set; }
        public double IngredientCost { get; set; }
    }

This is my delete operation:

    public void DeleteRecipe()
    {
        using (SQLiteConnection database = DependencyService.Get<ISQLite>().GetConnection())
        {
            var recipe = database.Get<Recipe_Model>(RecipeID);
            database.Delete(recipe, true);
        }
    }

What am I doing wrong?


Solution

  • Cascade operations only work for objects in memory. In your specific scenario, you are obtaining a single object from database via Get method and the cascade operations will delete all in-memory relationships, which is currently nothing because Ingredients property is null.

    If you don't already have the objects in memory, it doesn't make sense to load them just to get the identifiers to delete them, which is exactly what cascade deletion do:

    // This would work as it loads children to memory, but it's inefficient
    var recipe = database.GetWithChildren<Recipe_Model>(RecipeID);
    database.Delete(recipe, true);
    

    Instead, I'd recommend you to delete them manually:

    database.Execute("DELETE FROM [Ingredients_Model] WHERE [RecipeID] == ?", recipe.Id);
    database.Delete(recipe);