可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have the following ADO Model
Student
Id,Name
and
Course
Id,Name,Student_ID
I have made the following view for it
@model Tuple<MvcApplication4.Models.Course, MvcApplication4.Models.Student >
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Course</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Item1.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Item1.Name)
@Html.ValidationMessageFor(model => model.Item1.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Item1.S_ID, "Student")
</div>
<fieldset>
<legend>Student</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Item2.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Item2.Name)
@Html.ValidationMessageFor(model => model.Item2.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Item2.Class)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Item2.Class)
@Html.ValidationMessageFor(model => model.Item2.Class)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
</fieldset>
}
And the controller for it is as
public ActionResult Create()
{
return View();
}
//
// POST: /Default3/Create
[HttpPost]
public ActionResult Create(Tuple<Student ,Course > t)
{
try
{
// TODO: Add insert logic here
db.Students.AddObject(t.Item1);
db.SaveChanges();
t.Item2.S_ID = t.Item1.Id;
db.Courses.AddObject(t.Item2);
db.SaveChanges();
return RedirectToAction("Copy");
}
catch
{
return View();
}
}
But When i click the Creat button it gives the following Error
Server Error in '/' Application.
No parameterless constructor defined for this object.
回答1:
The Tuple<X, Y>
class doesn't have a default constructor so you will need to write a custom model binder if you want this to work. Another possibility is to use a custom view model which is what I would recommend you:
public class MyViewModel
{
public Course Course { get; set; }
public Student Student { get; set; }
}
and then:
public ActionResult Create()
{
return View(new MyViewModel());
}
//
// POST: /Default3/Create
[HttpPost]
public ActionResult Create(MyViewModel model)
{
try
{
// TODO: Add insert logic here
db.Students.AddObject(t.Student);
db.SaveChanges();
t.Course.S_ID = t.Student.Id;
db.Courses.AddObject(t.Course);
db.SaveChanges();
return RedirectToAction("Copy");
}
catch
{
return View(model);
}
}
and finally:
@model MvcApplication4.Models.MyViewModel
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Course</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Student.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Student.Name)
@Html.ValidationMessageFor(model => model.Student.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Student.S_ID, "Student")
</div>
<fieldset>
<legend>Student</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Course.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Course.Name)
@Html.ValidationMessageFor(model => model.Course.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Course.Class)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Course.Class)
@Html.ValidationMessageFor(model => model.Course.Class)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
回答2:
MVC is pretty smart, but it can't really figure out how to create a new instance of Tuple and create new instances of the items, then assign the proper items to it. That's just too complex of a task.
The error you get is because a Tuple doesn't have a default parameterless constructor, and requires new items to be passed to it in the constructor, something that MVC can't do.
You will have to break this down, and create your tuple in your controller action from a viewmodel that contains your items as members.
回答3:
You need to pass the model to your view.
Example:
return View(model);
回答4:
This seems to have resolved the issue for me as an alternative and it is working now:
[HttpGet]
public ActionResult Create()
{
Course course = new Course();
Student student = new Student();
var tuple = new Tuple<Course,Student>(course,student);
return View(tuple);
}
[HttpPost]
public ActionResult Create(Tuple<Course,Student> tuple){ do something ...}
I tried several other approaches include some that have been suggested here but, didn't resolve the problem. I just posted this to help someone else who might want to use Tuple though, use it only if you don't have another alternative.
回答5:
I got it to work after a few minutes of digging and some thinking. Here's a quick example of what I did:
GET action:
[HttpGet]
public ActionResult Update(int id = 0)
{
ProductDto product = _productService.FindByID(id);
SupplierDto supplier = _supplierService.FindByProductID(productId: product.ProductID);
return View(model: new Tuple<ProductDto, SupplierDto>(product, supplier));
}
POST action:
[HttpPost]
public JsonResult Update(int id = 0, ProductDto Item1, SupplierDto Item2)
{
// Get the product name
string productName = Item1.ProductName;
// Get the supplier name
string supplierName = Item2.SupplierName;
...
return Json(new { success = true });
}
View:
@model Tuple<ProductDto, SupplierDto>
@{
ViewBag.Title = "add title later ... ";
AjaxOptions options = new AjaxOptions { ... };
}
@using (Ajax.BeginForm("Update", "Product", options, htmlAttributes: new { @id = "update-form" }))
{
<fieldset>
<legend>Update Product</legend>
<div class="display-label">
@Html.LabelFor(model => model.Item1.ProductName)
</div>
<div class="display-field">
@Html.EditorFor(model => model.Item1.ProductName)
</div>
...
<div class="display-label">
@Html.LabelFor(model => model.Item2.SupplierName)
</div>
<div class="display-field">
@Html.EditorFor(model => model.Item2.SupplierName)
</div>
</fieldset>
<div class="submit-button">
<button type="submit" class="button">Update details</button>
<div>
}
回答6:
You should bind prefix in parameters
Controller:
public ActionResult ThisMethod([Bind(Prefix = "Item1")] AccountViewModel model)
{
// toDo
}
View:
@model Tuple<AccountViewModel>
@Html.EditorFor(model => model.Item1.Firstname)
回答7:
@DarinDimitri's solution is right but there is a way with Tuple as well. If you just change these code below you will get tuple models.
[HttpPost]
public ActionResult Create(Course Item1, Student Item2)
{
try
{
// TODO: Add insert logic here
db.Students.AddObject(Item2);
db.SaveChanges();
Item1.S_ID = Item2.Id;
db.Courses.AddObject(Item1);
db.SaveChanges();
return RedirectToAction("Copy");
}
catch
{
return View();
}