Примечание. Вчера я задал аналогичный вопрос, но с тех пор я перешел от этой проблемы к другой. Хотя это очень тесно связано, я думаю, что это лучше всего выразить в отдельном вопросе.
У меня три модели: Account
, AccountType
и Person
. Я хочу создать единую страницу формы, через которую новая учетная запись с определенным типом учетной записи и с определенной информацией о человеке может быть отправлена в базу данных.
public class AccountType
{
[Key]
public int AccountTypeID { get; set; }
[Required]
public string AccountTypeName { get; set; }
}
public class Person
{
[Key]
public int PersonID { get; set; }
// Bunch of properties not relevant to the question here...
}
public class Account
{
[Key]
public int AccountID { get; set; }
[ForeignKey("AccountType")]
public int AccountTypeID { get; set; }
[ForeignKey("Person")]
public int PersonID { get; set; }
// A few properties here...
public virtual AccountType AccountType { get; set; }
public virtual Person Person { get; set; }
}
Поскольку создание новой учетной записи требует от меня вставки в учетную запись, а также в таблицу пользователей, я создал модель представления для обеих этих моделей:
public class Register
{
public Account Account { get; set; }
public Person Person { get; set; }
}
В представлении «Регистрация» я просто привязал свойства моделей «Учетная запись» и «Человек» к полям формы. Я также использовал ViewBag для отображения списка типов учетных записей в раскрывающемся списке.
Часть, которую я не понимаю, находится в контроллере POST:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Register(Register Register)
{
if (ModelState.IsValid) {
_db.Accounts.Add(Register.Account);
_db.SaveChanges();
return View(Register);
}
// do something else
}
Проверка ModelState проходит успешно после комментирования параметра Nullable в файле проекта. Однако Register.Account имеет нулевые свойства:
Все значения, которые я привязывал в представлении «Реестр», устанавливаются корректно, но свойства навигации (Register.Account.AccountType
и Register.Account.Person
) я ни к чему не привязывал, так как не знал, что с ними делать.
Теперь я не могу вставить в базу данных приведенный выше код, потому что получаю ошибку ограничения внешнего ключа Person. Кажется, что Register.Account
не может иметь нулевых значений для своих свойств навигации Person
или AccountType
. Судя по всему, они должны быть установлены (или, по крайней мере, свойство Person
должно быть установлено).
Я знаю, что могу установить эти свойства навигации вручную в контроллере. Для Person
я могу написать что-то вроде этого перед сохранением в БД: Register.Account.Person = Register.Person
, и я также могу придумать что-то для AccountTypes
, чтобы придать ему правильное значение. Я проверил это, и он вставляется в базу данных.
Но это не кажется мне правильным подходом. Мне кажется, что должен быть лучший, более правильный способ прояснить отношения модели или таблицы к .NET перед вставкой в базу данных.
Кто-нибудь знает лучший способ?
PS: я использую .NET 6.
Я понимаю. Итак, должна ли моя модель представления просто служить хранилищем для свойств, которые я хочу захватить (привязать) из формы, чтобы в методе действия POST я мог создавать новые экземпляры моделей Account и Person, а затем заполнять их данные из модели представления? Хотя я, вероятно, мог бы понять это, было бы полезно увидеть пример кода.
Есть сторонние инструменты, которые могут помочь вам в этом. например dotnettutorials.net/lesson/automapper-in-c-sharp
По предложению Джереми я решил эту проблему, создав новую модель представления, которая включала только те свойства, которые мне нужно было связать, и опускала все свойства навигации, которые не были необходимы для успешной вставки в базу данных.
Ваша модель представления не должна раскрывать вашу модель данных, поскольку MVC с радостью привяжет все свойства.