c# - MVC 4 - 多对多关系和复选框

标签 c# asp.net-mvc entity-framework checkbox many-to-many

我正在使用 ASP.NET MVC 4 和 Entity Framework 。在我的数据库中,我有一个表订阅,它代表公共(public)交通的订阅。此订阅可以提供对多个公共(public)交通公司的访问(因此订阅可以有 1, 2, 3, ... 公司),那么这些表之间是多对多关系(我有它们之间的中间表)。

我想允许通过一个页面创建订阅,该页面将包含订阅的字段金额以及通过复选框显示的可用公司。每个复选框代表一个现有公司(存储在我的数据库中的公司)。

知道如何做到这一点吗?我读过这个ASP.NET MVC Multiple Checkboxes但这并没有真正的帮助。

编辑:这是我的表格图。

Tables Diagram

最佳答案

您从两个 View 模型开始。第一个代表选定的公司...

public class CompanySelectViewModel
{
    public int CompanyId { get; set; }
    public string Name { get; set; }
    public bool IsSelected { get; set; }
}

...以及要创建的订阅的第二个:

public class SubscriptionCreateViewModel
{
    public int Amount { get; set; }
    public IEnumerable<CompanySelectViewModel> Companies { get; set; }
}

然后在 SubscriptionController 的 GET 操作中,从数据库加载公司以初始化 View 模型:

public ActionResult Create()
{
    var viewModel = new SubscriptionCreateViewModel
    {
        Companies = _context.Companies
            .Select(c => new CompanySelectViewModel
            {
                CompanyId = c.CompanyId,
                Name = c.Name,
                IsSelected = false
            })
            .ToList()
    };

    return View(viewModel);
}

现在,您已拥有此操作的强类型 View :

@model SubscriptionCreateViewModel

@using (Html.BeginForm()) {

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

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

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

为了正确呈现公司复选框,您需要引入一个编辑器模板。它必须具有名称 CompanySelectViewModel.cshtml 并进入文件夹 Views/Subscription/EditorTemplates(如果不存在,请手动创建这样的文件夹)。这是一个强类型的部分 View :

@model CompanySelectViewModel

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

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

Name 添加为隐藏字段,以在 POST 期间保留名称。

显然,您必须对 View 进行更多样式设置。

现在,您的 POST 操作将如下所示:

[HttpPost]
public ActionResult Create(SubscriptionCreateViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        var subscription = new Subscription
        {
            Amount = viewModel.Amount,
            Companies = new List<Company>()
        };

        foreach (var selectedCompany
            in viewModel.Companies.Where(c => c.IsSelected))
        {
            var company = new Company { CompanyId = selectedCompany.CompanyId };
            _context.Companies.Attach(company);

            subscription.Companies.Add(company);
        }

        _context.Subscriptions.Add(subscription);
        _context.SaveChanges();

        return RedirectToAction("Index");
    }

    return View(viewModel);
}

除了使用 Attach 之外,您还可以先使用 var company = _context.Companies.Find(selectedCompany.CompanyId); 加载公司。但使用Attach,您无需往返数据库即可加载要添加到集合中的公司。

(编辑 2:this answer 中是具有相同示例模型的编辑操作和 View 的延续。)

编辑

您的模型并不是真正的多对多关系。相反,您有两个一对多关系。通常不需要 PublicTransportSubscriptionByCompany 实体。如果该表中有一个由 Id_PublicTransportSubscription、Id_PublicTransportCompany 组成的复合主键,并删除 id 列 Id_PublicTransportSubscriptionByCompanyId EF 会将此表架构检测为多对多关系,并且在订阅和公司的每个实体中创建一个集合,并且不会为链接表创建任何实体。我上面的代码将适用。

如果您出于某种原因不想更改架构,则必须更改 POST 操作,如下所示:

[HttpPost]
public ActionResult Create(SubscriptionCreateViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        var subscription = new Subscription
        {
            Amount = viewModel.Amount,
            SubscriptionByCompanies = new List<SubscriptionByCompany>()
        };

        foreach (var selectedCompany
            in viewModel.Companies.Where(c => c.IsSelected))
        {
            var company = new Company { CompanyId = selectedCompany.CompanyId };
            _context.Companies.Attach(company);

            var subscriptionByCompany = new SubscriptionByCompany
            {
                Company = company
            };

            subscription.SubscriptionByCompanies.Add(subscriptionByCompany);
        }

        _context.Subscriptions.Add(subscription);
        _context.SaveChanges();

        return RedirectToAction("Index");
    }

    return View(viewModel);
}

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

相关文章:

c# - 设计房屋的绘图面板

c# - 将 char 数组值从 C++ 传递到 C# 应用程序

c# - 重命名字段时如何禁用 Visual Studio 2015 灯泡?

asp.net-mvc - delphi web服务从.net mvc应用程序获取不同的日期时间

c# - Entity Framework - 如何将复杂对象添加到数据库

c# - 将数据表导出到 Excel 文件

asp.net - MVC ApiController JSON 对象根

asp.net-mvc - 参数字典包含参数的空条目

ASP.NET Entity Framework 4 导航实体不反射(reflect)对数据库所做的更改

c# - Azure SQL 数据库的暂时登录错误