ASP.NET MVC ID字段未填写数据库
我几乎是MVC的新手,并尝试创建一个用于数据管理的简单应用(MVC 5/vs 2022)使用本教程。我有两个课程以及他们的控制器和视图:站点和仓库。仓库与站点有关,因此这是其模型:
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
这是控制器:
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
这是创建仓库(仅“使用”零件)的视图:
@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
现在问题是,当我添加新仓库时,Site_ID在数据库中为null(我已经通过SSM手动填充了第一个):
当我从数据库中加载仓库时,这会导致空站点名称/ID。我该如何解决?
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(quot;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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
实体框架仅绑定数据库
表
和view
列列,而不是字段(EF Core确实直接支持更新字段,但是您假设您使用EF,而不是EF Core,而不是EF Core,因为据我所知,EF核心不支持vb.net)。从此更改您的班级成员....
...或此:
...或此(如果您是一个详细的表达受虐狂...):
其他要点:
ivalIdatableObject.validate
方法中直接访问数据库:这是您的控制器操作或应用程序的ASP.NET请求Prococessing Pipeline的责任方法旨在同步和快速,这意味着您不应该在其中进行任何IO。Entity Framework only binds database
TABLE
andVIEW
columns to properties, not fields (EF Core does support updating fields directly, but I assume you're using EF, not EF Core, because to my knowledge EF Core does not support VB.NET).Change your class' member from this....
...to this:
...or this (if you're a verbose-code masochist...):
Other points:
IValidatableObject.Validate
method: that's the responsibility of your Controller Action or some other part of your application's ASP.NET requesty-processing pipeline - theValidate
method is intended to be synchronous and fast which implies you should not be doing any IO in there.