Как обычно, когда вам не разрешено использовать опцию каскадного удаления (между прочим, ограничение SqlServer, в некоторых базах данных, таких как Oracle, таких проблем нет), вам необходимо (рекурсивно) удалить связанные данные перед удалением записи.
Это можно сделать по одному или по уровням (меньше команд SQL, но потенциально можно использовать большие списки IN
PK). Связанные данные также могут быть определены с помощью SQL на основе CTE - наиболее эффективного, но независимого от базы данных способа.
Следующий метод реализует второй подход:
static void DeleteItems(DbContext context, Expression<Func<Item, bool>> filter)
{
var items = context.Set<Item>().Where(filter).ToList();
if (items.Count == 0) return;
var itemIds = items.Select(e => e.Id);
DeleteItems(context, e => e.OptionalItemId != null && itemIds.Contains(e.OptionalItemId.Value));
context.RemoveRange(items);
}
и может использоваться в вашем коде следующим образом:
using (var context = CreateContext())
{
// Remove old items
DeleteItems(context, item => item.StockId == stock.Id);
// Remove optional items from another stock
DeleteItems(context, item => item.StockId == stock.RelatedStock.Id);
// The rest...
}