Вставка зависимого объекта с помощью 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);

В обоих случаях вам может не понадобиться идентификатор для обоих объектов. В качестве примечания конца, пожалуйста, поделитесь классом сопоставления, если это возможно.