Ответ 1
Когда дело доходит до базы данных, Наследование TPT реализуется с помощью Ассоциации общих первичных ключей между базовый класс (например, Product) и все производные классы (например, SpecializedProduct). Теперь, когда вы удаляете объект Customer без получения свойства Products, EF не знает, что у этого Клиента есть куча продуктов, которые также необходимо удалить согласно вашему требованию. Если вы включите каскадные удаления путем маркировки вашей ассоциации клиент-продукт по мере необходимости, тогда база данных позаботится об удалении дочерней записи из таблицы продуктов, но если эта дочерняя запись является специализированным продуктом, то соответствующая строка в SpecializedProduct не будет удалить и, следовательно, исключение, которое вы получаете. Поэтому в основном следующий код не будет работать:
// This works only if customer products are not SpecializedProduct
Customer customer = context.Customers.Single(c => c.CustomerId == 1);
context.Customers.Remove(customer);
context.SaveChanges();
Этот код заставит EF отправить в базу данных следующий SQL:
exec sp_executesql N'delete [dbo].[Customer] where ([CustomerId] = @0)',N'@0 int',@0=1
Тем не менее, нет возможности включить каскадное удаление между таблицами Product и SpecializedProduct, а именно, как EF Code First реализует наследование TPT, и вы не можете его переопределить.
Итак, какое решение?
Один из способов - это то, что вы уже выяснили, вручную переключая каскады между таблицами Product и SpecializedProduct, чтобы избежать исключения при удалении клиента с помощью SpecializedProducts.
Второй способ - позволить EF заботиться о клиенте SpecializedProducts при удалении клиента. Как я уже говорил, это происходит из-за того, что объект Customer не был правильно выбран, и EF не знает о специализации SpecializedProducts клиента, что означает, что, правильно загружая объект клиента, Ef начнет отслеживать ассоциации клиентов и будет предоставлять необходимые SQL-инструкции, чтобы убедиться что каждая связанная запись удаляется перед удалением клиента:
Customer customer = context.Customers
.Include(c => c.Products)
.Single(c => c.CustomerId == 1);
context.Customers.Remove(customer);
context.SaveChanges();
В результате EF отправит в базу данных следующие операторы SQL, которые отлично удаляют все по порядку:
exec sp_executesql N'delete [dbo].[SpecializedProduct] where ([Id] = @0)',N'@0 int',@0=1
exec sp_executesql N'delete [dbo].[Product] where (([Id] = @0) and ([Customer_CustomerId] = @1))',N'@0 int,@1 int',@0=1,@1=1
exec sp_executesql N'delete [dbo].[Customer] where ([CustomerId] = @0)',N'@0 int',@0=1