我正在使用 ASP.NET MVC 4 和 Entity Framework ,我正在寻找某种方法来从我的数据库中创建多对多关系和复选框以创建/编辑 Controller 和 View ,我找到了@Slauma 的答案在 MVC 4 - Many-to-Many relation and checkboxes 中创建,但是,我真的很想看看这如何扩展到编辑和删除功能以及此解决方案中的其他一些合作伙伴。有人可以展示我将如何在 Edit Controller 方法中填充 ClassificationSelectViewModel 以获取“已选中”和“未选中”值?这是一个 Matt Flowers 的问题,也能解决我的问题。

最佳答案

以下是 this answer 的延续,它描述了实体 CreateSubscription 之间具有多对多关系的模型的 Company. GET 和 POST 操作这里是 Edit 操作的过程,我将如何做(除了我可能不会将所有 EF 代码放入 Controller 操作中,但将其提取到扩展和服务方法中):
CompanySelectViewModel 保持不变:

public class CompanySelectViewModel
{
    public int CompanyId { get; set; }
    public string Name { get; set; }
    public bool IsSelected { get; set; }
}
SubscriptionEditViewModelSubscriptionCreateViewModel 加上 Subscription 的关键属性:
public class SubscriptionEditViewModel
{
    public int Id { get; set; }
    public int Amount { get; set; }
    public IEnumerable<CompanySelectViewModel> Companies { get; set; }
}
GET 操作可能如下所示:
public ActionResult Edit(int id)
{
    // Load the subscription with the requested id from the DB
    // together with its current related companies (only their Ids)
    var data = _context.Subscriptions
        .Where(s => s.SubscriptionId == id)
        .Select(s => new
        {
            ViewModel = new SubscriptionEditViewModel
            {
                Id = s.SubscriptionId
                Amount = s.Amount
            },
            CompanyIds = s.Companies.Select(c => c.CompanyId)
        })
        .SingleOrDefault();

    if (data == null)
        return HttpNotFound();

    // Load all companies from the DB
    data.ViewModel.Companies = _context.Companies
        .Select(c => new CompanySelectViewModel
        {
            CompanyId = c.CompanyId,
            Name = c.Name
        })
        .ToList();

    // Set IsSelected flag: true (= checkbox checked) if the company
    // is already related with the subscription; false, if not
    foreach (var c in data.ViewModel.Companies)
        c.IsSelected = data.CompanyIds.Contains(c.CompanyId);

    return View(data.ViewModel);
}
Edit View 是 Create View 加上 Subscription 的关键属性 Id 的隐藏字段:
@model SubscriptionEditViewModel

@using (Html.BeginForm()) {

    @Html.HiddenFor(model => model.Id)
    @Html.EditorFor(model => model.Amount)

    @Html.EditorFor(model => model.Companies)

    <input type="submit" value="Save changes" />
    @Html.ActionLink("Cancel", "Index")
}

选择公司的编辑器模板保持不变:
@model CompanySelectViewModel

@Html.HiddenFor(model => model.CompanyId)
@Html.HiddenFor(model => model.Name)

@Html.LabelFor(model => model.IsSelected, Model.Name)
@Html.EditorFor(model => model.IsSelected)

POST 操作可能是这样的:
[HttpPost]
public ActionResult Edit(SubscriptionEditViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        var subscription = _context.Subscriptions.Include(s => s.Companies)
            .SingleOrDefault(s => s.SubscriptionId == viewModel.Id);

        if (subscription != null)
        {
            // Update scalar properties like "Amount"
            subscription.Amount = viewModel.Amount;
            // or more generic for multiple scalar properties
            // _context.Entry(subscription).CurrentValues.SetValues(viewModel);
            // But this will work only if you use the same key property name
            // in ViewModel and entity

            foreach (var company in viewModel.Companies)
            {
                if (company.IsSelected)
                {
                    if (!subscription.Companies.Any(
                        c => c.CompanyId == company.CompanyId))
                    {
                        // if company is selected but not yet
                        // related in DB, add relationship
                        var addedCompany = new Company
                            { CompanyId = company.CompanyId };
                        _context.Companies.Attach(addedCompany);
                        subscription.Companies.Add(addedCompany);
                    }
                }
                else
                {
                    var removedCompany = subscription.Companies
                       .SingleOrDefault(c => c.CompanyId == company.CompanyId);
                    if (removedCompany != null)
                        // if company is not selected but currently
                        // related in DB, remove relationship
                        subscription.Companies.Remove(removedCompany);
                }
            }

            _context.SaveChanges();
        }

        return RedirectToAction("Index");
    }

    return View(viewModel);
}
Delete 操作不那么困难。在 GET 操作中,您可以加载一些订阅属性以显示在删除确认 View 中:
public ActionResult Delete(int id)
{
    // Load subscription with given id from DB
    // and populate a `SubscriptionDeleteViewModel`.
    // It does not need to contain the related companies

    return View(viewModel);
}

然后在 POST 操作中加载实体并删除它。不需要包含公司,因为在多对多关系(通常)中启用了链接表上的级联删除,以便数据库将负责删除链接条目和父 Subscription :
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirm(int id)
{
    var subscription = _context.Subscriptions.Find(id);
    if (subscription != null)
        _context.Subscriptions.Remove(subscription);

    return RedirectToAction("Index");
}

关于c# - MVC 4 编辑 Controller /查看多对多关系和复选框,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17812604/

10-13 09:09