I'm almost new to MVC and trying to create a simple app for data management (MVC 5/VS 2022) using this tutorial. I have two classes along with their controllers and views: Site and Warehouse. Warehouse is site-dependent, so this is its model:
Public Class Warehouse Implements IValidatableObject Private mId As Integer Private mSite As Site Private mWarehouseID As String Private mWarehouseName As String <Display(Name:="Site"), Required> Public SiteID As Integer <Key> Public Property Id As Integer Get Return mId End Get Set(value As Integer) mId = value End Set End Property <Display(Name:="Site")> Public Overridable Property Site As Site Get Return mSite End Get Set(value As Site) mSite = value End Set End Property <Display(Name:="Warehouse ID"), Required, Index(IsUnique:=True), MaxLength(20, ErrorMessage:="Maximum allowed length is 20 characters")> Public Property WarehouseID As String Get Return mWarehouseID End Get Set(value As String) mWarehouseID = value End Set End Property <Display(Name:="Warehouse Name"), Required, MaxLength(100, ErrorMessage:="Maximum allowed length is 100 characters")> Public Property WarehouseName As String Get Return mWarehouseName End Get Set(value As String) mWarehouseName = value End Set End Property Public Function Validate(validationContext As ValidationContext) As IEnumerable(Of ValidationResult) Implements IValidatableObject.Validate Dim db As New Data.KFI_IPPContext Dim vresult As New List(Of ValidationResult) Dim validatename = db.Warehouses.FirstOrDefault(Function(w) (w.WarehouseID = WarehouseID) And (w.Id <> Id)) If validatename IsNot Nothing Then Dim errmsg As New ValidationResult($"Warehouse {WarehouseID} already exists.") vresult.Add(errmsg) End If Return vresult End Function End Class And this is controller:
Public Class WarehousesController Inherits System.Web.Mvc.Controller Private db As New KFI_IPPContext ' GET: Warehouses Public Async Function Index(SearchString As String) As Threading.Tasks.Task(Of ActionResult) Dim warehouses = From w In db.Warehouses If String.IsNullOrEmpty(SearchString) Then warehouses = From w In warehouses Select w Else warehouses = From w In warehouses Where w.WarehouseName.Contains(SearchString) Or w.WarehouseID.Contains(SearchString) Or w.Site.SiteName.Contains(SearchString) End If Return View(Await warehouses.ToListAsync) End Function ' GET: Warehouses/Details/5 Function Details(ByVal id As Integer?) As ActionResult If IsNothing(id) Then Return New HttpStatusCodeResult(HttpStatusCode.BadRequest) End If Dim warehouse As Warehouse = db.Warehouses.Find(id) If IsNothing(warehouse) Then Return HttpNotFound() End If Return View(warehouse) End Function ' GET: Warehouses/Create Function Create() As ActionResult PopulateSiteList() Return View() End Function ' POST: Warehouses/Create 'To protect from overposting attacks, enable the specific properties you want to bind to, for 'more details see https://go.microsoft.com/fwlink/?LinkId=317598. <HttpPost()> <ValidateAntiForgeryToken()> Function Create(<Bind(Include:="Id,WarehouseID,WarehouseName")> ByVal warehouse As Warehouse) As ActionResult If ModelState.IsValid Then db.Warehouses.Add(warehouse) db.SaveChanges() Return RedirectToAction("Index") End If PopulateSiteList(warehouse.SiteID) Return View(warehouse) End Function ' GET: Warehouses/Edit/5 Function Edit(ByVal id As Integer?) As ActionResult If IsNothing(id) Then Return New HttpStatusCodeResult(HttpStatusCode.BadRequest) End If Dim warehouse As Warehouse = db.Warehouses.Find(id) If IsNothing(warehouse) Then Return HttpNotFound() End If PopulateSiteList(warehouse.SiteID) Return View(warehouse) End Function ' POST: Warehouses/Edit/5 'To protect from overposting attacks, enable the specific properties you want to bind to, for 'more details see https://go.microsoft.com/fwlink/?LinkId=317598. <HttpPost()> <ValidateAntiForgeryToken()> Function Edit(<Bind(Include:="Id,WarehouseID,WarehouseName")> ByVal warehouse As Warehouse) As ActionResult If ModelState.IsValid Then db.Entry(warehouse).State = EntityState.Modified db.SaveChanges() Return RedirectToAction("Index") End If PopulateSiteList(warehouse.SiteID) Return View(warehouse) End Function ' GET: Warehouses/Delete/5 Function Delete(ByVal id As Integer?) As ActionResult If IsNothing(id) Then Return New HttpStatusCodeResult(HttpStatusCode.BadRequest) End If Dim warehouse As Warehouse = db.Warehouses.Find(id) If IsNothing(warehouse) Then Return HttpNotFound() End If Return View(warehouse) End Function ' POST: Warehouses/Delete/5 <HttpPost()> <ActionName("Delete")> <ValidateAntiForgeryToken()> Function DeleteConfirmed(ByVal id As Integer) As ActionResult Dim warehouse As Warehouse = db.Warehouses.Find(id) db.Warehouses.Remove(warehouse) db.SaveChanges() Return RedirectToAction("Index") End Function Protected Overrides Sub Dispose(ByVal disposing As Boolean) If (disposing) Then db.Dispose() End If MyBase.Dispose(disposing) End Sub Private Sub PopulateSiteList(Optional SelectedSite As Object = Nothing) Dim sitequery = From s In db.Sites Order By s.SiteID Select s ViewData("SiteID") = New SelectList(sitequery, "SiteID", "SiteName", SelectedSite) End Sub End Class And this is view for creating warehouses (Only "Using" part):
@Using (Html.BeginForm()) @Html.AntiForgeryToken() @<div class="form-horizontal"> <h4>Warehouse</h4> <hr /> @Html.ValidationSummary(True, "", New With {.class = "text-danger"}) <div class="form-group"> <label for="SiteID" class="custom-select150">Site</label> <div class="col-md-10"> @Html.DropDownList("SiteID", Nothing, htmlAttributes:=New With {.class = "custom-select150"}) @Html.ValidationMessageFor(Function(model) model.SiteID, "", New With {.class = "text-danger"}) </div> </div> <div class="form-group"> @Html.LabelFor(Function(model) model.WarehouseID, htmlAttributes:=New With {.class = "control-label col-md-2"}) <div class="col-md-10"> @Html.EditorFor(Function(model) model.WarehouseID, New With {.htmlAttributes = New With {.class = "form-control"}}) @Html.ValidationMessageFor(Function(model) model.WarehouseID, "", New With {.class = "text-danger"}) </div> </div> <div class="form-group"> @Html.LabelFor(Function(model) model.WarehouseName, htmlAttributes:=New With {.class = "control-label col-md-2"}) <div class="col-md-10"> @Html.EditorFor(Function(model) model.WarehouseName, New With {.htmlAttributes = New With {.class = "form-control"}}) @Html.ValidationMessageFor(Function(model) model.WarehouseName, "", New With {.class = "text-danger"}) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div> End Using Now the problem is that when I add a new warehouse, Site_Id is NULL in database (I have filled the first one manually via SSMS):
This causes empty site name/ID when I load warehouses from database. How can I fix this?

Public SiteID As Integeris a field, not a property. EF requires DB table columns to be mapped to properties, not fields. Also, why are you using the very, very old-style of excessively verbose VB properties instead of the far more succinct auto-implemented property syntax: learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/…