Ado.net mvc3 tuple, which uses separate views in the model

I have the following ADO model

Student Id, Name and Course Id, Name, student_id

I made the following presentation for him

@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 him is like

 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, you get the following error

Server error in application "/".

There is no constructor without parameters for this object.

+6
source share
6 answers

The Tuple<X, Y> class does not have a default constructor, so you will need to write a custom mediator if you want this to work. Another option is to use a custom view model, which I would recommend to 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> } 
+11
source

MVC is pretty smart, but it cannot figure out how to create a new instance of Tuple and create new instances of the elements, and then assign the corresponding elements to it. This is too much of a challenge.

The error you get is that Tuple does not have a constructor without default parameters and requires new elements to be passed in the constructor, which MVC cannot do.

You will have to break this down and create your own tuple in your controller action from a view model containing your elements as members.

+2
source

You need to convey the model in your opinion. Example:

 return View(model); 
+2
source

This seems to have resolved the issue for me as an alternative, and now it works:

 [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: some of them were suggested here, but did not solve the problem. I just posted this to help someone else who can use Tuple, but use it only if you have no other alternative.

+1
source

I made him work after a few minutes of digging and thinking. Here is a brief 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> } 
0
source

You must bind the prefix in the parameters of the Controller:

 public ActionResult ThisMethod([Bind(Prefix = "Item1")] AccountViewModel model) { // toDo } 

View:

 @model Tuple<AccountViewModel> @Html.EditorFor(model => model.Item1.Firstname) 
0
source

Source: https://habr.com/ru/post/901416/


All Articles