MVC 4编辑控制器/查看多对多关系和复选框 [英] MVC 4 Edit Controller/ View Many to Many relation and checkboxes

查看:165
本文介绍了MVC 4编辑控制器/查看多对多关系和复选框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ASP.NET MVC 4和实体框架,我正在寻找一些方法来创建许多关系和复选框从我的数据库创建/编辑控制器和视图,我已经找到了@在 MVC 4 - 多对多关系和复选框中创建的Slauma答案但是,我真的很想看看这个解决方案如何扩展到编辑和删除功能以及其他一些合作伙伴。有人可以显示如何填充编辑控制器方法中的ClassificationSelectViewModel以获取已检查和未选中值?

解决方案

以下是这个答案描述创建对于具有多对多关系的模型的GET和POST操作订阅公司。以下是编辑动作我该怎么做(除了我可能不会把所有的EF代码放到控制器的动作中,而是将其解压缩到扩展和服务方式):



CompanySelectViewModel 保持不变:

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

SubscriptionEditViewModel SubscriptionCreateViewModel 加上订阅的主要属性:

  public class SubscriptionEditViewModel 
{
public int Id {get;组; }
public int Amount {get;组; }
public IEnumerable< CompanySelectViewModel>公司{get;组;
}

GET 动作可能如下所示:

  public ActionResult Edit(int id)
{
//加载从DB
//与其当前的相关公司(仅他们的ID)订阅所需的ID
var data = _context.Subscriptions
.Where(s => s.SubscriptionId = = id)
.Select(s => new
{
ViewModel = new SubscriptionEditViewModel
{
Id = s.SubscriptionId
Amount = s。金额
},
CompanyIds = s.Companies.Select(c => c.CompanyId)
})
.SingleOrDefault();

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

//从DB
data.ViewModel.Companies = _context.Companies
.Select(c => new CompanySelectViewModel
{
CompanyId = c.CompanyId,
Name = c.Name
})
.ToList();

//如果公司
//已经与订阅相关,则设置IsSelected标志:true(=复选框) false,如果不是
foreach(var.C in data.ViewModel.Companies)
c.IsSelected = data.CompanyIds.Contains(c.CompanyId);

return View(data.ViewModel);
}

编辑创建视图加上订阅的隐藏字段的主要属性 Id

  @model SubscriptionEditViewModel 

@using(Html.BeginForm()) {

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

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

< input type =submitvalue =保存更改/>
@ Html.ActionLink(取消,索引)
}

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

  @model CompanySelectViewModel 

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

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

动作可能是这样的:

  [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)
{
//更新标量属性,如Amount
subscription.Amount = viewModel.Amount;
//或更多通用的多个标量属性
// _context.Entry(subscription).CurrentValues.SetValues(viewModel);
//但是,只有在ViewModel和实体

foreach(var company in viewModel.Companies)中使用相同的关键属性名称
//时,这才有效
{
if(company.IsSelected)
{
if(!subscription.Companies.Any(
c => c.CompanyId == company.CompanyId))
{
//如果公司被选中但还没有
//在DB中相关,添加关系
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)
//如果公司未被选中,但目前为
//与DB相关,则删除关系
subscription.Companies.Remove(removedCompany);
}
}

_context.SaveChanges();
}

返回RedirectToAction(Index);
}

return View(viewModel);
}

删除不那么困难。在 GET 操作中,您可以加载一些订阅属性以显示在删除确认视图上:

  public ActionResult Delete(int id)
{
//从DB
//加载带有给定ID的订阅,并填充SubscriptionDeleteViewModel。
//不需要包含相关公司

return View(viewModel);
}

而在 POST 操作你加载实体然后删除它。没有必要包括这些公司,因为在多对多关系(通常)中,链接表上的级联删除被启用,以便数据库将负责删除链接条目以及父订阅

  [HttpPost,ActionName(Delete)] 
public ActionResult DeleteConfirm (int id)
{
var subscription = _context.Subscriptions.Find(id);
if(subscription!= null)
_context.Subscriptions.Remove(subscription);

return RedirectToAction(Index);
}


I'm working with ASP.NET MVC 4 and Entity Framework and I was searching for some way to make many to many relation and checkboxes from my db for a Create/Edit controller and view, I have found the answer with @Slauma answer for Create in MVC 4 - Many-to-Many relation and checkboxes but, I'd really like to see how this extends to Edit and Delete functionality as well like some other partners in this solution. Could someone please show how I would populate the ClassificationSelectViewModel in the Edit controller method to get both the "checked" and "unchecked" values? this is a Matt Flowers question that will solve mine too.

解决方案

The following is a continuation of this answer that describes Create GET and POST actions for a model with many-to-many relationship between entities Subscription and Company. Here is the procedure for the Edit actions how I would do it (except that I probably wouldn't put all the EF code into the controller actions but extract it into extension and service methods):

The CompanySelectViewModel remains unchanged:

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

The SubscriptionEditViewModel is the SubscriptionCreateViewModel plus the Subscription's key property:

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

The GET action could look like this:

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);
}

The Edit view is the Create view plus a hidden field for the Subscription's key property 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")
}

The editor template to select a company remains unchanged:

@model CompanySelectViewModel

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

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

And the POST action could be like this:

[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);
}

The Delete actions are less difficult. In the GET action you could load a few subscription properties to display on the delete confirmation 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);
}

And in the POST action you load the entity and delete it then. There is no need to include the companies because in a many-to-many relationship (usually) cascading delete on the link table is enabled so that the database will take care of deleting the link entries together with the parent 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");
}

这篇关于MVC 4编辑控制器/查看多对多关系和复选框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆