简体   繁体   English

带有ViewModel的ASP.NET MVC5控制器CRUD(2个模型)

[英]ASP.NET MVC5 Controller CRUD with ViewModel (2 models)

In my controller, I have a ViewModel containing 2 different models, called Drug and Food. 在我的控制器中,我有一个ViewModel,其中包含2个不同的模型,分别称为Drug和Food。

public class FoodDrugViewModel {
        public IEnumerable<SGHealthDesktop.Models.Drug> Drugs { get; set; }
        public IEnumerable<SGHealthDesktop.Models.Food> Foods { get; set; }

    }

In my MainController, this is how I pass in the ViewModel into the Index. 在我的MainController中,这就是我将ViewModel传递给Index的方式。

 // GET: Admin
        public ActionResult Index() {
            FoodDrugViewModel vm = new FoodDrugViewModel(); //initialize it
            vm.Drugs = db.Drugs.ToList();
            vm.Foods = db.Foods.ToList();
            return View(vm);
        }

In my view, I created two tables, and looped the items in each of the model, like this. 在我看来,我创建了两个表,并像这样循环了每个模型中的项目。

<table class="table" id="drugTable">
    <thead>
        <tr>
            <th>Drug Name</th>
            <th>Dosage</th>
            <th>Unit</th>
            <th>Type</th>
        </tr>
    </thead>
    @foreach (var item in Model.Drugs) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.DrugName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Dosage)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Unit)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Type)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id = item.DrugId }) |
                @Html.ActionLink("Details", "Details", new { id = item.DrugId }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.DrugId })
            </td>
        </tr>
    }
</table>

 @foreach (var item in Model.Foods) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.FoodName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Protein)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Carbohydrate)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.TotalFat)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id = item.FoodId }) |
            @Html.ActionLink("Details", "Details", new { id = item.FoodId }) |
            @Html.ActionLink("Delete", "Delete", new { id = item.FoodId })
        </td>
    </tr>
}

To prevent both tables from showing up at the same time, I used a dropdownlist accompanied with JQuery so user can choose which table to see, and it's working as expected. 为了防止两个表同时显示,我在JQuery中使用了一个下拉列表,以便用户可以选择要查看的表,并且该表按预期工作。 However, my issue are as follow . 但是,我的问题如下

When I click on the "Details" ActionLink, or infact any of the 3 ActionLinks (Detail, Edit, Delete), I would like the relevant information to be displayed. 当我单击“详细信息” ActionLink或保留3个ActionLink中的任何一个(详细信息,编辑,删除)时,我希望显示相关信息。 For example, if I'm viewing the Drug table and if I click on "Details", the Detail view will display the drug information, and the same for Food. 例如,如果我正在查看“药物”表,并且单击“详细信息”,则“详细信息”视图将显示药物信息,与“食品”信息相同。

However, I can't seem to figure out how that can be achieved. 但是,我似乎无法弄清楚该如何实现。 My Detail method is as follow, having Drug as the main model still. 我的Detail方法如下,仍然以Drug为主要模型。 How can it detect if the user has chose to view the detail of Drug OR Food? 如何检测用户是否选择查看药品或食品的详细信息? As you can see in the code, it immediately finds the Drug details based on the id. 如您在代码中所见,它会立即根据ID查找药物详细信息。

// GET: Admin/Details/5
        public ActionResult Details(int? id) {
            if (id == null) {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Drug drug = db.Drugs.Find(id);
            if (drug == null) {
                return HttpNotFound();
            }
            return View(drug);
        }

As for Create, there's no problem with it as I can again, allow a dropdownlist so user can choose what type, Drug or Food, they want to create and the form will be shown respectively (assuming in view I'm using the FoodDrugViewModel instead of Drug model). 至于Create,我再也没有问题,允许一个下拉列表,以便用户可以选择要创建的类型,Drug或Food,然后分别显示表单(假设我使用的是FoodDrugViewModel药物模型)。 But how can i bind the data in the controller? 但是我如何绑定控制器中的数据? By default, the Create method is as follow. 默认情况下,Create方法如下。

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "DrugId,DrugName,Dosage,Unit,Type")] Drug drug) {
            if (ModelState.IsValid) {
                db.Drugs.Add(drug);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(drug);
        }

Any help rendered will be much appreciated. 任何帮助将不胜感激。 Thanks in advance! 提前致谢!

UPDATE: Issue on Create() 更新:关于Create()的问题

In the Create view, I declared the FoodDrugViewModel as follow 在创建视图中,我声明了FoodDrugViewModel如下

@model SGHealthDesktop.ViewModels.FoodDrugViewModel @model SGHealthDesktop.ViewModels.FoodDrugViewModel

And my Drug form looks like this (the same applies for Food). 我的药物表格看起来像这样(食品也一样)。

<div id="drugDiv">
            <div class="form-group">
                @Html.LabelFor(model => model.Drug.DrugName, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Drug.DrugName, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Drug.DrugName, "", new { @class = "text-danger" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.Drug.Dosage, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Drug.Dosage, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Drug.Dosage, "", new { @class = "text-danger" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.Drug.Unit, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Drug.Unit, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Drug.Unit, "", new { @class = "text-danger" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.Drug.Type, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownListFor(model => model.Drug.Type,
                     new SelectList(new[]
                    { "Diabetic Medication", "Hypertension", "Kidney Disease", "Insulin", "High Cholesterol"
                    }) as SelectList, new { @class = "btn btn-default dropdown-toggle form-control" })

                    @Html.ValidationMessageFor(model => model.Drug.Type, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

My Create() method is as follow 我的Create()方法如下

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "DrugName,Dosage,Unit,Type")] FoodDrugViewModel vm) {
            try {
                if (ModelState.IsValid) {
                    if (vm.Drug != null) {
                        db.Drugs.Add(vm.Drug);
                    } 
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
            } catch (DataException dex) {
                //Log the error (uncomment dex variable name and add a line here to write a log.
                System.Diagnostics.Debug.WriteLine(dex);
                ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
            }
            return View(vm.Drug);
        }

I placed a breakpoint at the line the method is called, and "Drug" is null. 我在调用该方法的行上放置了一个断点,“ Drug”为空。 May I know where did I went wrong? 我可以知道我哪里出了错吗? :( :(

You can pass one more parameter to your ActionResult to differentiate between Drug and Food . 您可以ActionResult传递一个参数,以区分DrugFood For an example, I would be adding type param, with value drug and food for respective actions. 例如,我将添加param type ,并为相应的操作添加有价值的drugfood

Drug 药物


@foreach (var item in Model.Drugs) {
<tr>
  <td>
    @Html.DisplayFor(modelItem => item.DrugName)
  </td>
  <td>
    @Html.DisplayFor(modelItem => item.Dosage)
  </td>
  <td>
    @Html.DisplayFor(modelItem => item.Unit)
  </td>
  <td>
    @Html.DisplayFor(modelItem => item.Type)
  </td>
  <td>
    @Html.ActionLink("Edit", "Edit", new { id = item.DrugId, type="drug" }) | @Html.ActionLink("Details", "Details", new { id = item.DrugId, type="drug" }) | @Html.ActionLink("Delete", "Delete", new { id = item.DrugId, type="drug" })
  </td>
</tr>
} 

Food 餐饮


@foreach (var item in Model.Foods) {
<tr>
  <td>
    @Html.DisplayFor(modelItem => item.FoodName)
  </td>
  <td>
    @Html.DisplayFor(modelItem => item.Protein)
  </td>
  <td>
    @Html.DisplayFor(modelItem => item.Carbohydrate)
  </td>
  <td>
    @Html.DisplayFor(modelItem => item.TotalFat)
  </td>
  <td>
    @Html.ActionLink("Edit", "Edit", new { id = item.FoodId, type="food" }) | @Html.ActionLink("Details", "Details", new { id = item.FoodId, type="food" }) | @Html.ActionLink("Delete", "Delete", new { id = item.FoodId, type="food" })
  </td>
</tr>
}

Your ActionResult Details now should be accepting two arguments, id and type . 现在,您的ActionResult Details应该接受两个参数idtype

// GET: Admin/Details/5
public ActionResult Details(int? id, string type) {
  //You do not want to do anything if you don't have type value too, so the condition
  if (id == null || string.IsNullOrEmpty(type)) {
    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  }
  if(type=="drug"){
      Drug drug = db.Drugs.Find(id);
      if (drug == null) {
         return HttpNotFound();
      }
      return View(drug);
  }
  else
  {
      Food food = db.Foods.Find(id);
      if (food == null) {
         return HttpNotFound();
      }
      return View(food);
  }
}

Hope you will be handling your view efficiently with different models passed. 希望您将通过传递的不同models 有效地处理视图。


EDIT 编辑

You might also check it in below way, by adding ternary operation, but am not sure whether it will work or not. 您也可以通过以下方式通过添加三元运算来检查它,但不确定是否可以运行。 You can give a try. 你可以试试看。

// GET: Admin/Details/5
public ActionResult Details(int? id, string type) {
  //You do not want to do anything if you don't have type value too, so the condition
  if (id == null || string.IsNullOrEmpty(type)) {
    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  }
  var model=type=="drug"?db.Drugs.Find(id):db.Foods.Find('id');
  if (model == null) {
      return HttpNotFound();
  }
  return View(model);
}

I can suggest you two ways to do this. 我可以建议您两种方法。

  1. For both Drugs and Foods create 6 different actions like 为药物和食物创建6种不同的动作,例如

Food_Edit, Food_Details, Food_Delete, Drug_Edit, Drug_Details, Drug_Delete Food_Edit,Food_Details,Food_Delete,Drug_Edit,Drug_Details,Drug_Delete

  1. Pass Another parameter for the actions indicating the type. 为指示类型的动作传递另一个参数。 In that case you may have to right another routing method. 在这种情况下,您可能必须纠正另一种路由方法。

@Html.ActionLink("Edit", "Edit", new { id = item.FoodId, type="Food" }) @ Html.ActionLink(“ Edit”,“ Edit”,新的{id = item.FoodId,type =“ Food”})

@Html.ActionLink("Edit", "Edit", new { id = item.DrugId, type="Drug" }) @ Html.ActionLink(“ Edit”,“ Edit”,新的{id = item.DrugId,type =“ Drug”})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM