Вставка зависимого объекта с помощью ApplicationUser
У меня есть следующие объекты:
public class ApplicationUser : IdentityUser
{
...
public int? StudentId { get; set; }
public virtual Student Student { get; set; }
}
public class Student
{
public int Id { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
}
И я пытаюсь создать нового пользователя и ученика приложения, поэтому я делаю это:
var user = new ApplicationUser() {
Name = "test",
UserName = "test",
Student = new Student ()
};
var result = await userManager.CreateAsync(user, "test12345!");
Результат имеет успех, два объекта вставляются в базу данных, но Student.UserId имеет значение null
Как я могу вставить оба объекта и их отношения?
Я попытался установить student.UserId = user.Id, но затем я получаю исключение с этим сообщением: "Невозможно определить допустимый порядок для зависимых операций"
Ответы
Ответ 1
Проблема и решение приведены здесь Индивидуальные отношения с необязательным зависимым концом, использующим соглашения по умолчанию и здесь EF Code First - 1-к-1 дополнительные отношения. Но позвольте мне добавить что-то к теме.
Конструкция вашей сущности создает избыточность в таблице db, связанной с ApplicationUser
, но что более важно, она создает цикл связей внешних ключей между двумя таблицами. Хотя технически это возможно, чтобы справиться с такими отношениями, это кошмар для обслуживания, и его следует избегать.
Красота первого подхода EF-кода заключается в том, что вам не нужно думать о таких вещах. Не пытайтесь создавать свои POCO, как таблицы db. За исключением первичного ключа, не используйте свойства xxxId. Используйте правильно настроенные свойства навигации, чтобы выразить отношения между вашими объектами и позволить EF заботиться о дизайне db.
Учитывая все это:
Сначала удалите свойство StudentId
из класса ApplicationUser
и UserId
из класса Student
. Обратите внимание, что это приведет к удалению столбца StudentId
из соответствующей таблицы db, поэтому вы можете начать работу с новой db или использовать миграции.
Затем используйте следующую конфигурацию:
modelBuilder.Entity<ApplicationUser>()
.HasOptional(u => u.Student)
.WithRequired(s => s.User).Map(a => a.MapKey("UserId"));
и ваша проблема должна быть решена.
Ответ 2
Вы ищете одно (нулевое или одно) отношение между учеником и пользователем приложения. Таким образом, для одного пользователя может быть или не быть учеником.
В этом случае вам не нужен идентификатор пользователя приложения в классе ученика, или если вы хотите, то это будет ваш базовый класс.
modelBuilder.Entity<ApplicationUser>()
.HasKey(t => t.StudentId);
// Map one-to-zero or one relationship
modelBuilder.Entity<ApplicationUser>()
.HasRequired(t => t.Student)
.WithOptional(t => t.ApplicationUser);
Вместо этого, если вы ищете отношения один к одному
modelBuilder.Entity<ApplicationUser>()
.HasKey(t => t.StudentId);
modelBuilder.Entity<Instructor>()
.HasRequired(t => t.Student)
.WithRequiredPrincipal(t => t.ApplicationUser);
В обоих случаях вам может не понадобиться идентификатор для обоих объектов. В качестве примечания конца, пожалуйста, поделитесь классом сопоставления, если это возможно.