ASP.NET MVC ID字段未填写数据库

发布于 2025-02-12 12:28:30 字数 8706 浏览 5 评论 0原文

我几乎是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):

enter image description here

This causes empty site name/ID when I load warehouses from database. How can I fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一曲琵琶半遮面シ 2025-02-19 12:28:30

实体框架仅绑定数据库view列列,而不是字段(EF Core确实直接支持更新字段,但是您假设您使用EF,而不是EF Core,而不是EF Core,因为据我所知,EF核心不支持vb.net)。

从此更改您的班级成员....

    <Display(Name:="Site"), Required>
    Public SiteID As Integer

...或此:

    <Display(Name:="Site"), Required>
    Public Property SiteId As Integer

...或此(如果您是一个详细的表达受虐狂...)

    Private mSiteId As Integer

    ' [etc]

    <Display(Name:="Site"), Required>
    Public Property SiteId As Integer
        Get
            Return mSiteId
        End Get
        Set(value As Integer)
            mSiteId = value
        End Set
    End Property

其他要点:

  • 您不应该将EF Entity类作为DTO或ViewModels进行表单结合 - 它引入了安全漏洞(“超稳定性”),并且使软件更难维护,因为您无法与实体类别分开版本DTO和表单。
  • 验证不是验证。您不应直接从ivalIdatableObject.validate方法中直接访问数据库:这是您的控制器操作或应用程序的ASP.NET请求Prococessing Pipeline的责任方法旨在同步和快速,这意味着您不应该在其中进行任何IO。
    • 验证是确保该数据上提交的数据符合某些不变约束的过程(例如,电话数格式,非空名称等)。
    • 验证涉及实际腿部工作对实际验证 recript ,而不是仅仅是有效有效
      • “正确”数据是一组有效数据的子集。

Entity Framework only binds database TABLE and VIEW 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....

    <Display(Name:="Site"), Required>
    Public SiteID As Integer

...to this:

    <Display(Name:="Site"), Required>
    Public Property SiteId As Integer

...or this (if you're a verbose-code masochist...):

    Private mSiteId As Integer

    ' [etc]

    <Display(Name:="Site"), Required>
    Public Property SiteId As Integer
        Get
            Return mSiteId
        End Get
        Set(value As Integer)
            mSiteId = value
        End Set
    End Property

Other points:

  • You should not be using EF entity classes as DTOs or ViewModels for form-bindings - it introduces security vulnerabilities ("overposting") as well as makes software harder to maintain because you can't version DTOs and forms separately from entity classes.
  • Validation is not verification. You should not be accessing your database directly from within your IValidatableObject.Validate method: that's the responsibility of your Controller Action or some other part of your application's ASP.NET requesty-processing pipeline - the Validate method is intended to be synchronous and fast which implies you should not be doing any IO in there.
    • Validation is the process of ensuring submitted data conforms with some invariant constraints on that data (e.g. phone-number formatting, non-empty names, etc).
    • Verification involves doing actual leg-work to actually verify that submitted data is correct, instead of merely valid.
      • "Correct" data is a subset of the set of valid data.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文