【问题标题】:Update a related list before posting parent model - MVC 5 EF 6在发布父模型之前更新相关列表 - MVC 5 EF 6
【发布时间】:2015-04-19 14:21:11
【问题描述】:

我确定这完全是菜鸟问题。我目前正在处理两个主要实体:

请求 - 发送给采购部门的请求,详细说明与采购请求相关的信息。

namespace Purchasing.Models
{
public class Request
{
    public long ID { get; set; }

    [DisplayName("Total")]
    [Required]
    public decimal total { get; set; }

    [DisplayName("Date Created")]
    public DateTime dateCreated { get; set; }

    [DisplayName("Date Updated")]
    public DateTime dateModified { get; set; }

    [DisplayName("Reason for Purchase")]
    [Required]
    public string justification { get; set; }

    [Required]
    //[ForeignKey("User_ID")]
    public string userID { get; set; }

    [DisplayName("Current Status")]
    public Enums.RequestStatus status { get; set; }

    [DisplayName("Items")]
    [Required]
    public virtual ICollection<RequestLine> RequestLines { get; set; }

    [DisplayName("Budget")]
    [Required]
    public long budgetID { get; set; }
}

public class RequestDbContext : DbContext
{
    public RequestDbContext() : base("RequestDbContext")
    {
    }

    public static RequestDbContext Create()
    {
        return new RequestDbContext();
    }

    public DbSet<Request> Requests { get; set; }

    public System.Data.Entity.DbSet<RequestLine> RequestLines { get; set; }

    public System.Data.Entity.DbSet<Budget> Budgets { get; set; }
}
}

RequestLine - 要包含在采购请求中的单个项目的行项目详细信息。

namespace Purchasing.Models
{
    public class RequestLine
    {
        public long ID { get; set; }

        [DisplayName("Description")]
        [Required]
        public string description { get; set; }

        [DisplayName("Quantity")]
        [Required]
        public decimal quantity { get; set; }

        [DisplayName("Price")]
        [Required]
        public decimal price { get; set; }

        [DisplayName("Amount")]
        public decimal amount { get; set; }

        public long requestID { get; set; }
        [Required]
        [ForeignKey("ID")]
        public Request Request { get; set; }
    }
}

我想要完成的是一个视图,可以在请求发布之前将 RequestLines 添加到请求中。

请求控制器:

// GET: Request/Create
        public ActionResult Create()
        {
            string userID = User.Identity.GetUserId();
            ApplicationUser currentUser = userDb.Users.FirstOrDefault(x => x.Id == userID);

            if(currentUser != null)
            {
                ViewData["UserFullName"] = currentUser.FirstName + " " + currentUser.LastName;
                ViewData["UserDepartment"] = currentUser.Department.ToString();
            }

            Request request = new Request();
            request.dateCreated = DateTime.Now;
            request.RequestLines = new List<RequestLine>();

            request.userID = currentUser.Id.ToString();

            return View(request);
        }

// POST: Request/Create
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "ID,total,dateCreated,dateModified,justification,userID,status,RequestLines")] Request request)
        {
            if (ModelState.IsValid)
            {
                request.status = Enums.RequestStatus.New;

                foreach (RequestLine reqLine in request.RequestLines)
                {

                    request.total += reqLine.amount;
                    reqLine.requestID = request.ID;
                    db.RequestLines.Add(reqLine);
                }

                db.Requests.Add(request);
                db.SaveChanges();

                return RedirectToAction("Index");
            }

            return View(request);
        }

我最终要实现的是创建请求的视图,该视图将允许用户为请求创建 RequestLines,并在发布整个请求之前将它们显示在创建视图中。

Request/Create.cshtml(表格现在由 Angular 显示,但没有执行后端数据绑定。

@model Purchasing.Models.Request
@using Purchasing.Models

@{
ViewBag.Title = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Create</h2>


@using (Html.BeginForm()) 
{
@Html.AntiForgeryToken()

<div class="form-horizontal" ng-controller="reqLineCtrl">
    <h4>Request</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })

    <div class="form-group">
        <div class="col-md-2">
            <b>@ViewData["UserFullName"]</b>
        </div>
        <div class="col-md-2">
            <b>@ViewData["UserDepartment"]</b>
        </div>
        <div class="col-md-2">
        </div>
        <div class="col-md-2">
            <b>@Model.dateCreated.ToString("MM/dd/yyyy")</b>
        </div>
    </div>
    <hr/>

    <div class="form-group">
        <div class="col-md-2">
            <label class="control-label" for="items">Items</label>
        </div>
        <div class="col-md-10">
            <table class="table" id="items">
                <caption><b>Request Total: ${{total | currency}}</b></caption>
                <tr>
                    <th>Description</th>
                    <th>Quantity</th>
                    <th>Price</th>
                    <th>Total</th>
                </tr>
                <tr ng-repeat="reqLine in lines">
                    <td>{{reqLine.description}}</td>
                    <td>{{reqLine.quantity}}</td>
                    <td>{{reqLine.price | currency}}</td>
                    <td>{{reqLine.price * reqLine.quantity | currency}}</td>
                </tr>
            </table>
        </div>
    </div>

    <div class="form-inline">
        <div class="form-group col-md-2">
            <label class="control-label col-md-6" for="quantity">Quantity</label>
            <div class="col-md-6">
                <input type="text" id="quantity" class="form-control" ng-model="line.quantity">
            </div>
        </div>

        <div class="form-group col-md-5">
            <label class="control-label col-md-2" for="description">Description</label>
            <div class="col-md-10">
                <input type="text" id="description" class="form-control" ng-model="line.description">
            </div>
        </div>

        <div class="form-group col-md-2">
            <label class="control-label col-md-6" for="price">Price</label>
            <div class="col-md-6">
                <input type="text" id="price" class="form-control" ng-model="line.price">
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="button" value="Add Item" class="btn btn-primary" ng-click="enterLine(line)"/>
            </div>
        </div>
    </div>
    <br/>
    <hr/>


    <div class="form-group">
        @Html.LabelFor(model => model.justification, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.justification, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.justification, "", new { @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-primary" />
        </div>
    </div>
</div>


}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}

我找到了多个关于 Html.RenderPartial、Html.Action、Ajax.BeginForm() 的教程,但我无法真正让它们适应我想要完成的任务。我不反对发送 JsonResults。我正在开发一个没有这些问题的 MEAN 堆栈应用程序,所以我对 JSON 很满意。最终,我知道必须有一种更清洁、更标准化的方式来执行此操作,因为它似乎是 Web 应用程序的常见操作。

我不想承认,但我已经被困在这一点上三周了,我的大部分时间都花在了试图找到解决方案的教程上。任何帮助将不胜感激,即使它只是将我指向一个实际上有我需要的答案的教程。

【问题讨论】:

    标签: entity-framework asp.net-mvc-5 asp.net-ajax action renderpartial


    【解决方案1】:

    如果我正确理解您的要求,MVC 的答案是您的 ng-repeat 应该替换为 C# foreach,它遍历 RequestLine 列表并显示它们。您需要创建一个显示模板和/或编辑器模板,以便您可以使用Html.DisplayFor() 和/或Html.EditorFor(),MVC 将知道如何显示每个RequestLine。在 Angular 术语中,您的显示或编辑器模板是 ng-repeat 中的任何内容。

    如果您想在不访问服务器的情况下创建一个新的RequestLine,您将需要 javascript 来复制现有的,清除字段并将其附加到列表中。 MVC 没有规定任何特定的执行方式,因为它是一个服务器端 MVC 框架,而不是像 Angular 这样的客户端框架。

    如果您想在客户端代码中使用 Angular,则不应使用 ASP.NET MVC。两者不混。 ASP.NET MVC 假设模型位于服务器上(因此您迭代项目的方式是在服务器上使用foreach),而 Angular 假设模型位于客户端上(因此您使用ng-repeat)。它必须是其中之一。 Angular 应该得到 ASP.NET Web API 的支持。

    评论后编辑:

    Ajax 表单只是一种序列化表单并将其发布到操作方法的方法,而无需编写任何 javascript。如果您愿意,您可以将RequestLine 的列表包含在 Ajax 表单中,并且删除、添加等操作将涉及到服务器的访问。这不会是一个很好的用户体验。

    您要做的是在客户端上构建一个列表,然后提交整个视图。 http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ 有一篇文章描述了如何做到这一点。您将不得不编写一些杂乱无章的 javascript 来实现这一点。由于模型位于服务器上,ASP.NET MVC 不能很好地做到这一点。好处是使用单一验证规则在客户端和服务器上进行无缝验证。

    【讨论】:

    • 在您的第二段中:“如果您想创建一个新的 RequestLine 而无需访问服务器,您将需要 javascript 来复制现有的,清除字段并将其附加到列表中。”这是 Ajax 表单的用武之地吗?摆脱 Angular 没有问题。我在这里使用它是因为我无法找到正确的解决方案并且必须有一些东西来演示。
    猜你喜欢
    • 2017-01-29
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多