Во-первых, у меня уже есть свой собственный способ решить эту проблему, но это своего рода воспроизведение настроек свойств и не использование API отслеживания изменений напрямую (путем доступа к DbEntityEntry
или даже ObjectStateManager
.
Поэтому я хотел бы знать, как API отслеживания изменений может использоваться непосредственно в этом случае. Вот участвующие классы:
public class TestContext : DbContext
{
public virtual DbSet<Class> Classes { get; set; }
public virtual DbSet<Person> Persons { get; set; }
}
public class Class
{
public Class()
{
Persons = new HashSet<Person>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual HashSet<Person> Persons { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int ClassId { get; set; }
[ForeignKey(nameof(ClassId))]
[Required]
public virtual Class Class { get; set; }
}
Сценарий здесь для отдельного DbContext, то есть он размещен на некотором удаленном сервисе, в то время какданные модели - все, что мы имеем в качестве входных данных.
//suppose we have an existing (loaded before from db) person here
//now on client side, we set its Class to a new instance
//and hope that it should be created after saving
person.Class = new Class { Name = "D" };
person.ClassId = 0;
//now on remote server side, we have the input person
//This is NOT working
using(var tc = new TestContext()){
tc.Persons.Attach(person);
tc.Classes.Add(person.Class);
tc.SaveChanges();
}
Вышеуказанный удаленный код не работает, экземпляр Class
может быть сохранен в порядке, но исключение все еще выдается (в строке tc.SaveChanges()
жаловаться, что существует несоответствие между принципалом и зависимым. Я понимаю, что вновь созданный Class
должен иметь автоматически сгенерированный Id
синхронизированный со свойством ClassId
person
(которое все еще 0
после сохранения).
Поэтому, если вам не нужно 2 вызова на SaveChanges
, первый вызов - сначала сохранить Class
перед обновлением ClassId
для person
w.Это второй вызов SaveChanges
, примерно так:
//This is working
using(var tc = new TestContext()){
tc.Classes.Add(person.Class);
tc.SaveChanges();
tc.Persons.Attach(person);
person.ClassId = person.Class.Id;
tc.SaveChanges();
}
Это, конечно, не очень хорошее решение.Очень хорошее решение для этого (как я уже упоминал в начале), но оно не использует API отслеживания изменений напрямую.Он просто пытается воспроизвести изменения после присоединения person
, например:
//This is working
using(var tc = new TestContext()){
var tempClass = person.Class;
person.Class = null;
tc.Persons.Attach(person);
person.Class = tempClass;
tc.SaveChanges();
}
Приведенный выше код выглядит намного лучше и работает просто отлично.Но это также выглядит немного хакерским.
Я ищу хорошее решение, использующее API отслеживания изменений напрямую, а не хакерское, как в последнем фрагменте кода выше.