#c# #entity-framework #asp.net-core #.net-core #.net-6.0
#c# #entity-framework #asp.net-core #.net-core #.net-6.0
Вопрос:
Я пытаюсь выполнить обновление с .NET 3.1 до .NET 6. Мне удалось собрать все и обновить различные пакеты NuGet в моем решении.
После попытки запуска моих модульных тестов я столкнулся с некоторыми странными проблемами с некоторыми операциями EF. Я использую поставщика базы данных в памяти для этих модульных тестов.
У меня есть настройка, подобная следующей:
Сущности:
public class EntityA
{
public Guid Id { get; set; }
public Guid? EntityBId { get; set; }
public EntityB EntityB { get; set; }
}
public class EntityB
{
public Guid Id { get; set; }
public string Name { get; set; }
}
Конфигурации:
public class EntityAConfiguration: IEntityTypeConfiguration<EntityA>
{
public void Configure(EntityTypeBuilder<EntityA> builder)
{
builder.ToTable("EntitiyAs");
builder.Property(e => e.Id)
.HasColumnName("EntitiyAId")
.IsRequired();
builder.HasKey(e => e.Id)
.HasName("PK_EntityAs");
builder.HasIndex(e => e.EntityBId)
.HasName("IX_EntityAs_EntityBId");
builder.HasOne(e => e.EntityB)
.WithMany()
.HasForeignKey(e => e.EntityBId)
.HasConstraintName("FK_EntityA_EntityBs_EntityBId");
}
}
public class EntityBConfiguration: IEntityTypeConfiguration<EntityB>
{
public void Configure(EntityTypeBuilder<EntityB> builder)
{
builder.ToTable("EntityBs");
builder.Property(e => e.Id)
.HasColumnName("EntityBId")
.IsRequired();
builder.HasKey(e => e.Id)
.HasName("PK_EntityBs");
}
}
Создание моего тестового DbContext следующим образом:
private TestDbContext GenerateDbContext()
{
var options = new DbContextOptionsBuilder<TestDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.EnableSensitiveDataLogging()
.Options;
return new TestDbContext(options);
}
В моих тестах я предварительно заполняю несколько из этих объектов в DbContext перед выполнением метода, который я хочу протестировать. Тестируемый метод выглядит следующим образом:
public async Task RemoveEntityBFromAssociatedEntityA(Guid entityBId)
{
var entityB = await _dbContext.EntityBs.SingleOrDefaultAsync(g => g.Id == entityBId);
if (entityB == null)
{
// throw exception...
}
var entityA = await _dbContext.EntityAs.SingleOrDefaultAsync(s => s.EntityBId == entityB);
if (entityA == null)
{
// throw exception...
}
entityA.EntityBId = null;
_dbContext.entityAs.Update(entityA);
await _dbContext.SaveChangesAsync();
}
Что я здесь делаю, так это удаляю ассоциацию с EntityB
on EntityA
, устанавливая идентификатор навигации на null. Как ни странно, эффект, который это имеет, заключается в том, что EntityA
он помечается для удаления, когда для него EntityBId
установлено значение null, и когда SaveChanges
вызывается, он фактически удаляет EntityA
.
Для меня это не имеет большого смысла. Почему EntityA
в этом сценарии он будет удален? Я просмотрел критические изменения как в EF Core 5, так и в EF Core 6, но я не вижу ничего, что могло бы вызвать это.
Комментарии:
1. Происходит ли это также в реальном приложении? Вы не должны использовать базу данных в памяти для тестирования .
2. Я также изначально думал, что это может быть проблема с использованием поставщика в памяти, но я попытался отключить его для Sqlite, и возникла та же проблема.
3. Тогда это выглядит как еще одна ошибка в EF core 6. Пожалуйста, проверьте проблемы с github, если сообщалось о подобных ошибках.
4. Я думаю, что это может быть как-то связано с обнуляемыми ссылочными типами и тем, как ядро EF обрабатывает это. В моем проекте включен параметр nullable. Обратите внимание, что свойство навигации
EntityBId
вEntityA
является обнуляемым идентификатором Guid, но свойство объекта не обнуляемо. Я только что попытался сделать это также обнуляемым (public EntityB? EntityB { get; set; }
), и, похоже , это решило проблему. Так ли мы должны определять необязательные отношения, когда NRT теперь включен?5. @AndyFurniss вы проверили, настроено ли отношение как обязательное и каскадное? Я думаю, что это может быть проблемой, потому
EntityB
что свойство не обнуляется, что приводит к требуемому отношению (которое каскадируется по умолчанию) и, следовательноEntityA
, будет каскадироваться, как только его связь сEntityB
будет разорвана. Возможно, попробуйте создать миграцию и проверить, изменился ли снимок модели.