首页 > 解决方案 > 如何为复杂的 EF 模型制作 Razor 表单

问题描述

我开始怀疑我要问的是否可能。但应该是。

MS示例与我所追求的相差甚远,所以也许E​​F的设计方式不是我想的那样。(顺便说一句,每个单独表的 CRUD Scaffold 效果很好。但它只创建表级别。我想要将关系作为对象管理的东西。)

public class ContactPhone
{
    public ContactPhone(ContactPhone contactPhone)
    {
        Id = contactPhone.Id;
        ContactId = contactPhone.ContactId;
        ContactPhoneTypeId = contactPhone.ContactPhoneTypeId;
        Number = contactPhone.Number;
    }

    //private ContactPhone contactPhone;

    public ContactPhone()
    {
    }

    //public ContactPhone(ContactPhone contactPhone)
    //{
    //    this.contactPhone = contactPhone;
    //}

    public int Id { get; set; }

    public int ContactId { get; set; }
    public virtual Contact Contact { get; set; }

    public int ContactPhoneTypeId { get; set; }
    public virtual ContactPhoneType ContactPhoneType { get; set; }

    public string Number { get; set; }
}


public class Contact
{
   public  Contact()
    {
        Phones = new List<ContactPhone>();
    }
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }

    public int LocationAddressId { get; set; }
    public LocationAddress LocationAddress { get; set; }

    public int UserId { get; set; }
    [ForeignKey("UserId")]
    public virtual SCPI_site_User User { get; set; }

    //public ICollection

    public List<ContactPhone> Phones { get; set; }
}

我知道这是错误的,但它有点工作......我的假设是我的联系人是持久的并且在 Razor 页面之间来回传递,但似乎并非如此。

            public class CreateModel : PhoneTypesPageModel
            {
                private readonly SCPI_Site.Areas.SCPI_SiteContext _context;

                public CreateModel(SCPI_Site.Areas.SCPI_SiteContext context)
                {
                    _context = context;
                }
                [TempData]
                public string Message { get; set; }

                [BindProperty]
                public Contact Contact { get; set; }

                [BindProperty]
                public ContactPhone ContactPhone { get; set; }

                //public bool HasPhones => Contact.Phones.Count > 0;

                public IActionResult OnGet()
                {
                    PopulatePhoneTypeDropDownList(_context);
                    int userID = User.Identity.GetUserId<int>();

                    if (Contact == null)
                    {
                        Contact = new Contact();
                    }
                    if (ContactPhone == null)
                    {
                        Contact = new Contact();
                    }

                    Contact.UserId = userID;
                    ViewData["UserId"] = userID;          
                    return Page();
                }

                public async Task<IActionResult> OnPostAsync(string submit)
                {
                    int userID = User.Identity.GetUserId<int>();
                    Contact.UserId = userID;        

                    switch (submit)
                    {
                        case "AddPhone":
                            // (failed attempt) _context.ContactPhone.Add(ContactPhone);
                            Contact.Phones.Add(new ContactPhone(ContactPhone));
                            ContactPhone.Number = "";
                            return Page();


                        default:
                            //if (!ModelState.IsValid)
                            //{
                            //    return Page();
                            //}

                            _context.Contact.Add(Contact);
                            await _context.SaveChangesAsync();
                            Message = "Contact Created!";

                            return RedirectToPage("./Index");
                    }

                }
            }
        }

HTML:

    @page

    @model SCPI_Site.Areas.ContactModel.Pages.Contacts.CreateModel

    @{
        //Layout = "~/Views/Shared/_AdminLayout.cshtml";
        ViewData["Title"] = "Create";
    }
    <div class="col">
        <h4>Contact</h4>
        <hr />
        <div class="row">
            <div class="col-md-4">
                <form method="post">
                    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                    <input type="hidden" asp-for="Contact.UserId" />
                    <div class="row">
                        <div class="form-group col-md-6">
                            <label asp-for="Contact.FirstName" class="control-label"></label>
                            <input asp-for="Contact.FirstName" class="form-control" />
                            <span asp-validation-for="Contact.FirstName" class="text-danger"></span>
                        </div>
                        <div class="form-group col-md-6">
                            <label asp-for="Contact.LastName" class="control-label"></label>
                            <input asp-for="Contact.LastName" class="form-control" />
                            <span asp-validation-for="Contact.LastName" class="text-danger"></span>
                        </div>
                    </div>

                    <div class="form-group">
                        <label asp-for="Contact.Email" class="control-label"></label>
                        <input asp-for="Contact.Email" class="form-control" />
                        <span asp-validation-for="Contact.Email" class="text-danger"></span>
                    </div>

                    <div class="form-group">
                        <label asp-for="Contact.LocationAddress.Address" class="control-label"></label>
                        <input asp-for="Contact.LocationAddress.Address" class="form-control" />
                        <span asp-validation-for="Contact.LocationAddress.Address" class="text-danger"></span>
                    </div>
                    <div class="row">
                        <div class="form-group col-md-4">
                            <label asp-for="Contact.LocationAddress.City" class="control-label"></label>
                            <input asp-for="Contact.LocationAddress.City" class="form-control" />
                            <span asp-validation-for="Contact.LocationAddress.City" class="text-danger"></span>
                        </div>
                        <div class="form-group col-md-4">
                            <label asp-for="Contact.LocationAddress.State" class="control-label"></label>
                            <input asp-for="Contact.LocationAddress.State" class="form-control" />
                            <span asp-validation-for="Contact.LocationAddress.State" class="text-danger"></span>
                        </div>
                        <div class="form-group col-md-4">
                            <label asp-for="Contact.LocationAddress.PostalCode" class="control-label"></label>
                            <input asp-for="Contact.LocationAddress.PostalCode" class="form-control" />
                            <span asp-validation-for="Contact.LocationAddress.PostalCode" class="text-danger"></span>
                        </div>
                    </div>

                    @if (Model.Contact.Phones != null)
                    {
                        <hr />
                        <table class="table">
                            <thead>
                                <tr>
                                    <th>
                                        Type
                                        @*@Html.DisplayNameFor(model => model.Contact.Phones[0].ContactPhoneType)*@
                                    </th>
                                    <th>
                                        Number
                                        @*@Html.DisplayNameFor(model => model.Contact.Phones[0].Number)*@
                                    </th>
                                    <th></th>
                                </tr>
                            </thead>
                            <tbody>
                                @if (Model.Contact.Phones != null)
                                {
                                    @foreach (var item in Model.Contact.Phones)
                                    {
                                        <tr>
                                            <td>
                                                @Html.DisplayFor(modelItem => item.ContactPhoneType.Id)
                                            </td>
                                            <td>
                                                @Html.DisplayFor(modelItem => item.Number)
                                            </td>
                                            <td>
                                                <a asp-page="../ContactPhones/Edit" asp-route-id="@item.Id">Edit</a> |
                                                <a asp-page="../ContactPhones/Details" asp-route-id="@item.Id">Details</a> |
                                                <a asp-page="../ContactPhones/Delete" asp-route-id="@item.Id">Delete</a>
                                            </td>
                                        </tr>
                                    }
                                }
                            </tbody>
                        </table>
                    }
                    <div class="form-group">
                        <input type="submit" value="Create" class="btn btn-default" />
                    </div>

                    <div id="pay-invoice" class="card">
                        <div class="card-body">
                            <div class="card-title">
                                <input type="hidden" id="x_card_num" name="x_card_num" value="">
                                @*<partial name="../ContactPhones/Index" model=@Model />*@


                                @*First name:
                                <input type="text" name="A" value="<%= ViewData[" A"] %>" />
                                <br />
                                Last name:
                                <input type="text" name="B" value="<%= ViewData[" B"] %>" />
                                <br />
                                <input type="submit" value="Insert" />
                                <button type="submit" name="submit" value="add"><span class="glyphicon glyphicon-plus"></span>Add another</button>*@



                                <input type="hidden" asp-for="ContactPhone.ContactId" />
                                <div class="row">
                                    <div class="form-group col-md-7">
                                        <label asp-for="ContactPhone.Number" class="control-label"></label>
                                        <input asp-for="ContactPhone.Number" class="form-control" />
                                        <span asp-validation-for="ContactPhone.Number" class="text-danger"></span>
                                    </div>
                                    <div class="form-group col-md-5">
                                        <label asp-for="ContactPhone.ContactPhoneType" class="control-label"></label>
                                        <select asp-for="ContactPhone.ContactPhoneTypeId" class="form-control"
                                                asp-items="@Model.PhoneTypeSL">
                                            @*<option value="">-- Select Type --</option>*@
                                        </select>
                                        <span asp-validation-for="ContactPhone.ContactPhoneTypeId" class="text-danger" />
                                    </div>
                                </div>

                                <button type="submit" name="submit" value="AddPhone" class="btn btn-primary"><span class="fa fa-plus"> </span>  Add Phone Number</button>

                                @*<a asp-area="ContactsModel" asp-page="/ContactPhones/Create"> Add Phone Number</a>*@
                            </div>
                        </div>
                    </div>

                    <p>

                        @*    <a asp-page="Create">Create New</a>*@
                    </p>

                    @*@Html.Hidden("Contact.UserId")   This breaks the validation*@
                    @*<div class="form-group">
                            <label asp-for="Contact.UserId" class="control-label"></label>
                            <select asp-for="Contact.UserId" class="form-control" asp-items="ViewBag.UserId"></select>
                        </div>*@




                </form>
            </div>
        </div>

        <div>
            <a asp-page="Index">Back to List</a>
        </div>
    </div>
    @section Scripts {
        @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}

创造:

鉴于这个小模型,我如何创建一个剃须刀页面,它将电话记录添加到联系人对象并捕获联系人对象数据并通过一次保存调用创建整个模型。(管理钥匙等)

现在我可能会在这里偏离基础,但这种类型的场景是我对 ORM 的期望。坦率地说,我不确定为什么有人会构建 EF 而不提供这种类型的功能。但很可能我遗漏了一些东西,我已经多次翻阅 MS 文档以寻找线索。

但它在 Django 中是这样工作的;)

如果甚至有一个此类操作的示例不是同一个客户一维示例,我将不胜感激。

谢谢 CB

标签: c#entity-frameworkentity-framework-6asp.net-core-2.1razor-pages

解决方案


如果要将项目绑定到某种集合的属性,则需要将索引器添加到表单字段的名称或传递给asp-fortaghelper 属性的表达式中,以0.

这是一个更简单的模型:

public class Order
{
    public int OrderId { get; set; }
    public string Customer { get; set; }
    public List<OrderItem> Items { get; set; }
}

public class OrderItem
{
    public int OrderItemId { get; set; }
    public string Item { get; set; }
    public decimal Price { get; set; }
}

这是页面模型:

public class CreateModel : PageModel
{
    [BindProperty]
    public Order Order { get; set; }

    public void OnPost()
    {

    }
}

这是表格:

@page
@model CreateModel
@{
}

<form method="post">
    <input asp-for="Order.Customer" /><br />
    <input asp-for="Order.Items[0].Item" /><br/>
    <input asp-for="Order.Items[0].Price" />
    <input type="submit"/>
</form>

这就是你所需要的。表单中的值将自动绑定到Order标有该属性的[BindProperty]属性。如果您将其传递给 EF,它将创建并保存一个订单,然后使用该 ID 创建并保存一个OrderItem. 如果您想允许用户创建更多项目,只需1为每个项目增加索引器:

<form method="post">
    <input asp-for="Order.Customer" /><br />
    @for (var i = 0; i < 5; i++)
    {
    <input asp-for="Order.Items[i].Item" /><br/>
    <input asp-for="Order.Items[i].Price" />
    }
    <input type="submit"/>
</form>

参考:https ://www.learnrazorpages.com/razor-pages/model-binding#binding-complex-collections


推荐阅读