'How Should I Set Navigation Properties Before Inserting Into The Database?

Note: I asked a similar question yesterday, but I've since moved past that problem into another issue. Although it's very closely related, I think it's best expressed in a separate question.

I have three models: Account, AccountType, and Person. I want to make a single form page, through which a new Account, with a specific AccountType, and with specific Person information could be POSTed to the database.

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; }
}

Since creating a new account requires me to insert into the account as well as the person table, I created a view model for both of these models:

public class Register
{
    public Account Account { get; set; }
    public Person Person { get; set; }
}

In the Register view, I simply bound the properties from the Account and Person models to form fields. I also used a ViewBag to display a list of AccountTypes in a dropdown.

The part that I don't understand is in the POST controller:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Register(Register Register)
{
    if (ModelState.IsValid) {
        _db.Accounts.Add(Register.Account);
        _db.SaveChanges();
        return View(Register);
    }
    // do something else
}

The ModelState check passes successfully, after having commented out the Nullable setting in the project file. However, Register.Account has null properties:

Register.Account has empty navigation properties

All the values that I bound in the Register view get set correctly, but I did not bind the navigation properties (Register.Account.AccountType and Register.Account.Person) to anything, since I did not know what to do with them.

Now, I can't insert into the database with the above code, because I get a Person foreign key constraint error. It seems that Register.Account cannot have null values for its Person or AccountType navigation properties. Apparently, they must be set (or, at least, the Person property must be).

I know that I can set these navigation properties manually in the controller. For Person, I can write something like this before saving to the DB: Register.Account.Person = Register.Person, and I can likewise come up with something for AccountTypes to give it its proper value. I've tested this, and it does insert into the database.

But, this doesn't strike me as the right approach. It seems to me that there must be a better, more proper way of clarifying the model or table relationships to .NET before inserting into the database.

Does anybody know a better way?

P.S.: I'm using .NET 6.



Solution 1:[1]

Per Jeremy's suggestion, I solved this problem by creating a new View Model, which only included the properties that I needed to bind, and omitting any navigation properties that weren't necessary to insert into the database successfully.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Skjervoy