Я создал образец репо для демонстрации проблемы.
Сущность:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Attributes
{
public Person Person { get; set; }
public string Attribs { get; set; }
}
Конфигурация DbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Attributes>()
.Property<int>("PersonId");
modelBuilder.Entity<Attributes>()
.HasKey("PersonId");
modelBuilder.Entity<Attributes>()
.HasOne(_ => _.Person)
.WithOne()
.IsRequired();
modelBuilder.Entity<Attributes>()
.Property(_ => _.Attribs)
.HasColumnName("Attributes");
}
Что очень хорошо работает для атрибутов?
- Чтение
- Обновление
- Удалить
Создать не работает.
Несмотря на то, что новый экземпляр Атрибуты добавлен в DbSet , он не помечен как Добавлен и, следовательно, не передан в базу данных. Пометка состояния сущности явно как Добавлено правильно фиксирует экземпляр в БД. Эта явность необходима только для Атрибутов . Все остальные объекты в моем реальном проекте правильно добавляются через DbSet.Add ().
Что не так с моими ожиданиями?
static void Main(string[] args)
{
using (var dbContext = new Context())
{
// reading works well
var readEntity = dbContext.Set<Attributes>()
.First(_ => _.Person.Id == 1);
Console.WriteLine($"Read entity has attributes value: {readEntity.Attribs}");
}
using (var dbContext = new Context())
{
var person = dbContext.Set<Person>().First(_ => _.Id == 2);
var attributes = new Attributes
{
Person = person,
Attribs = "some"
};
var state = dbContext.Set<Attributes>().Add(attributes);
Console.WriteLine($"State: {state.State}");
var count = dbContext.SaveChanges();
Console.WriteLine($"Changes written: {count}");
if (count == 0)
{
Console.WriteLine("Trying again with explicitly setting entity state to Added.");
state.State = Microsoft.EntityFrameworkCore.EntityState.Added;
count = dbContext.SaveChanges();
Console.WriteLine($"Changes written in second try: {count}");
}
}
Console.WriteLine("done");
Console.ReadLine();
}