У меня есть база данных с двумя разными путями к определенному объекту, один путь с DeleteBehavior.Cascade, а другой с DeleteBehavior.Restrict, чтобы избежать ошибки нескольких каскадных путей при создании базы данных. Это работает, как я и ожидал, при локальном запуске с использованием IIS Express и SQL Server Visual Studio в памяти, но выдает ошибку в модульных тестах, проверяющих ту же функциональность.
Пример:
public class Account
{
public string Id { get; set; }
}
Каждая учетная запись может иметь подписки:
public class Subscription
{
public string Id { get; set; }
// relationships
public string AccountId { get; set; }
public Account Account { get; set; }
}
Контакты могут быть как у аккаунтов, так и у подписок (это может не иметь особого смысла, но это просто пример, на самом деле моя модель сложнее, но по сути она сводится к следующему):
public class Contact
{
public string Id { get; set; }
// relationships
public string AccountId { get; set; }
public Account Account { get; set; }
public string SubscriptionId { get; set; }
public Subscription Subscription { get; set; }
}
Я хочу, чтобы любые контакты удалялись, если либо аккаунт, либо подписка будут удалены. Это моя конфигурация построителя моделей для контактов:
public void Configure(EntityTypeBuilder<Contact> entity)
{
entity.HasOne(e => e.Account)
.WithMany()
.HasForeignKey(e => e.AccountId)
.OnDelete(DeleteBehavior.Restrict);
entity.HasOne(e => e.Subscription)
.WithMany()
.HasForeignKey(e => e.SubscriptionId)
.OnDelete(DeleteBehavior.Cascade);
}
конфиг для подписок:
public void Configure(EntityTypeBuilder<Subscription> entity)
{
entity.HasOne(e => e.Account)
.WithMany()
.HasForeignKey(e => e.AccountId)
.OnDelete(DeleteBehavior.Cascade);
}
Идея заключалась в том, что при удалении учетной записи подписки будут удалены с помощью поведения удаления Cascade, и это удалит контакты, а поведение Restrict между учетными записями и контактами решит ошибку «множественных каскадных путей».
Это работает, когда я запускаю локально, я могу удалить учетную запись, и все подписки и контакты удаляются, ошибки нет. Проблема заключается в модульных тестах (с использованием xUnit), которые используют SQLite в памяти. Я хочу проверить, что удаление учетной записи приведет к удалению всех контактов:
[Fact]
public async Task DeleteAccount_ContactIsDeleted()
{
using (var factory = new ContextFactory()) // same connection will be used within using block
{
using (var context = factory.CreateContext())
{
await context.SeedDatabaseOneContactAsync(); // inserts account, subscription and contact into database
}
using (var context = factory.CreateContext())
{
Assert.Single(context.Contacts);
Assert.Single(context.Subscriptions);
Assert.Single(context.Accounts);
var account = await context.Accounts.SingleAsync();
context.Remove(account);
await context.SaveChangesAsync();
Assert.Empty(context.Contacts);
Assert.Empty(context.Accounts);
Assert.Empty(context.Subscriptions);
}
}
}
Однако это вызывает следующую ошибку
Сообщение: Microsoft.EntityFrameworkCore.DbUpdateException: произошла ошибка при обновлении записей. Подробности смотрите во внутреннем исключении. ---- Microsoft.Data.Sqlite.SqliteException: ошибка SQLite 19: «Ошибка ограничения FOREIGN KEY».
на линии
await context.SaveChangesAsync();
Я хотел бы знать, является ли это проблемой с SQLite, или я что-то делаю неправильно с моей моделью или конфигурацией?
Примечание. Я использую Entity Framework Core 2.1.1, и эти отношения обязательны (не могут быть нулевыми).