MVC Multiple Models in One View - c#

I want to reach multiple models in one view. I have DAL folder and DbContext.
class CvContext : DbContext
{
public CvContext() : base("CvContext")
{
}
public DbSet<LinkModel> Links { get; set; }
public DbSet<AboutModel> Abouts { get; set; }
public DbSet<PortfolioModel> Portfolios { get; set; }
public DbSet<SkillModel> Skills { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
And HomeController
public class HomeController : Controller
{
private CvContext db = new CvContext();
public ActionResult Index()
{
return View(db.Links.ToList());
}
}
Index.cshtml
#model IEnumerable<MvcCv.Models.LinkModel>
<ul>
#foreach (var item in Model)
{
<li>
<a href="#Html.DisplayFor(modelItem => item.LinkUrl)">
#Html.DisplayFor(modelItem => item.LinkName)
<span class="icon"></span>
<span class="menu-icon">
<img src="#Url.Content(item.LinkImage)" alt="" />
</span>
</a>
</li>
}
</ul>
How can i reach all models? I will use foreach for item in Model like Links. Thanks.

You should create a view model as follows:
public class FooViewModel
{
public IEnumerable<LinkModel> Links { get; set; }
public IEnumerable<AboutModel> Abouts { get; set; }
public IEnumerable<PortfolioModel> Portfolios { get; set; }
public IEnumerable<SkillModel> Skills { get; set; }
}
Then from your controller populate them as to your requirements, as an example:
public ActionResult Index()
{
var model = new FooViewModel();
model.Links = db.Links.ToList();
model.Abouts = db.Abouts.ToList();
model.Portfolios = db.Portfolios.ToList();
model.Skills = db.Skills.ToList();
return View(model);
}
Then change the model in your view to FooViewModel and all your properties will be available in there.
#model FooViewModel
<ul>
#foreach (var item in Model.Links)
{
<li>
#item
</li>
}
</ul>
<ul>
#foreach (var item in Model.Links)
{
<li>
#item
</li>
}
</ul>
// ....etc, obviously change the outputs as needed.

//suppose you have two Models
public class student
{
public int Id
public string Name{get;set;}
}
public class class
{
public int Id
public string Name{get;set;}
}
// Now combine these two class Model in single Model for example:
public class Mixmodel
{
public Student student {get;set;}
public Class class {get;set;}
}
//here is the Home controller of the Index view
#model projectName.MixModel
#foreach(var item in Model.class)
{
#html.displayfor(item.class.Name)
}
#foreach(var item in Model.student)
{
#html.displayfor(item.student.Name)
}

Related

Configure many-to-many relationship in ASP.NET Core MVC and Entity Framework against

I am trying to configure the relationship many-to-many between two tables, Employee and Project.
One Employee can participate in many projects, and one project can have many Employees working on it. So I created two model classes Employee and Project, and I added the table Employee_Project.
These are my three model classes:
namespace WebApp2.Models
{
public class Employee
{
[Key]
public int Emp_Id { get; set; }
public string Emp_Name { get; set; }
public string Emp_Email { get; set; }
public string Emp_Mobile { get; set; }
public virtual ICollection<Employee_Project> Employee_Projects { get; set; }
}
public class Project
{
[Key]
public int Proj_Id { get; set; }
public string Proj_Name { get; set; }
public string Project_Details { get; set; }
public virtual ICollection<Employee_Project> Employee_Projects { get; set; }
}
public class Employee_Project
{
[Key]
[Column(Order =1)]
public int Emp_Id { get; set; }
[Key]
[Column(Order = 2)]
public int Proj_Id { get; set; }
public virtual Employee Employee { get; set; }
public virtual Project Project { get; set; }
}
}
I then added this DbContext class:
namespace WebApp2.Data
{
public class MyDbContext:DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> option):base(option)
{
}
public DbSet<Employee> Employees { get; set; }
public DbSet<Project> Projects { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee_Project>().HasKey(pt => new { pt.Proj_Id, pt.Emp_Id });
modelBuilder.Entity<Employee_Project>()
.HasOne(pt => pt.Employee)
.WithMany(pt => pt.Employee_Projects)
.HasForeignKey(p => p.Emp_Id);
modelBuilder.Entity<Employee_Project>()
.HasOne(pt => pt.Project)
.WithMany(pt => pt.Employee_Projects)
.HasForeignKey(p => p.Proj_Id);
}
public DbSet<Employee_Project> Employee_Projects { get; set; }
}
}
I created after that the three controllers
public class ProjectController : Controller
{
private readonly MyDbContext _context;
public ProjectController(MyDbContext context)
{
_context = context;
}
public IActionResult Index()
{
return View(_context.projects.ToList());
}
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create(Project project)
{
_context.projects.Add(project);
_context.SaveChanges();
return RedirectToAction("Index");
}
}
public class EmployeeController : Controller
{
private readonly MyDbContext _context;
public EmployeeController(MyDbContext context)
{
_context = context;
}
public IActionResult Index()
{
return View(_context.Employees.ToList());
}
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create(Employee employee)
{
_context.Employees.Add(employee);
_context.SaveChanges();
return RedirectToAction("Index");
}
}
public class Emp_ProjController : Controller
{
private readonly MyDbContext _DbContext;
public Emp_ProjController(MyDbContext DbContext)
{
_DbContext = DbContext;
}
public IActionResult Index()
{
return View(_DbContext.Employee_Projects.ToList());
}
public IActionResult Create()
{
ViewBag.emp=_DbContext.Employees.ToList();
ViewBag.pro=_DbContext.projects.ToList();
return View();
}
[HttpPost]
public IActionResult Create(int empid, int [] projIds)
{
foreach (var item in projIds)
{
Employee_Project emp = new Employee_Project();
emp.Emp_Id = empid;
emp.Proj_Id = item;
_DbContext.Employee_Projects.Add(emp);
_DbContext.SaveChanges();
}
return RedirectToAction("Index");
}
}
After that foreach Controllers I made the view for the method Index and Create
Emp_Proj
//view Index
#model IEnumerable<WebApp2.Models.Employee_Project>
#{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Employee.Emp_Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Project.Proj_Name)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Employee.Emp_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Project.Proj_Name)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</tbody>
</table>
//view Create
<h2>Create</h2>
<form method="post">
<div>
<label>Employee Name</label>
#Html.DropDownList("empid", new SelectList(ViewBag.emp, "Emp_Id","Emp_Email"),"Select Employee")
</div>
<div>
<label>Select Project</label>
#* #Html.DropDownList("proid", new SelectList(ViewBag.pro, "Proj_Id","Proj_Name"),"Select Project")*#
<ul>
#foreach(var item in ViewBag.pro )
{
<li>
<input type="checkbox" name="projIds" value="#item.Proj_Id">#item.Proj_Name
</li>
}
</ul>
<input type="submit" value="SaveData"/>
</div>
</form>
I don't have problem in the Employee and the project, I found the problem when I want to create a Emp_Proj element
enter image description here
It always gives me an error like that:
SqlException: Violation of PRIMARY KEY constraint 'PK_Employee_Projects'. Cannot insert duplicate key into object 'dbo.Employee_Projects'. Duplicate key value: (1, 1).
The instruction has been terminated.
enter image description here
Can someone please help me to find the problem? Thanks in advance.
I try to find the problem, and I appreciate some assistance.
The error message has show the reason why cause this exception: The database already contains this record, you can't insert duplicate data. You just need to check if it already exists in the database before inserting data, Please refer to this simple demo.
[HttpPost]
public IActionResult Create(int empid, int[] projIds)
{
foreach (var item in projIds)
{
//check if the database already has this record
var empdb = _DbContext.Employee_Projects.Where(x => x.Emp_Id == empid && x.Proj_Id == item).FirstOrDefault();
if (empdb==null)
{
Employee_Project emp = new Employee_Project();
emp.Emp_Id = empid;
emp.Proj_Id = item;
_DbContext.Employee_Projects.Add(emp);
}
}
_DbContext.SaveChanges();
return RedirectToAction("Index");
}
First off, try to remove "Employee_Project" entity entirely, and see if EF Core can auto-create it. EF Core should be able to auto-generate the association table as long as the two navigational properties are set on the two Entities. Note that navigational properties of the two entities are supposed to reference each other. like so;
in Employee;
public virtual ICollection<Project> Projects { get; set; }
and in Project;
public virtual ICollection<Employee> Employees { get; set; }
In case that doesn't work, modify your Employee_Project class like this;
public class Employee_Project
{
[Key]
[Column(Order =1)]
public int EmployeeId { get; set; }
[Key]
[Column(Order = 2)]
public int ProjectId { get; set; }
public virtual Employee Employee { get; set; }
public virtual Project Project { get; set; }
}
The naming of the columns might have been the problem.

how to retrieve parent data and child data in the same view

I want to retrieve the data of parent and child in the same view mvc5 c#
<ul class="circle2">
<li style=" border:0px">
<div class="text">#Html.DisplayFor(model => model.Name)</div>
</li>
<ul class="circle3">
#foreach (var item1 in Model)
{
<li>
<div class="text">#Html.Display(modelItem => item1.Name)</div>
</li>
}
<li>
<div class="text" data-toggle="tooltip" data-placement="left" title="add family member">#Html.ActionLink("+", "Create")</div>
</li>
Your model must look like this:
public class newtree
{
public string User_ID { get; set; }
public string Name { get; set; }
public string perantID { get; set; }
List<Child> Children { get; set; }
}
You need to fill up the Children-list with the correct data, then iterate it with #foreach (var item1 in Model.Children)
Model
public class EmployeeViewModel {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public EmployeeDepartment employeeDepartment { get; set; }
}
public class EmployeeDepartment {
public int Id { get; set; }
public string DepartmentName { get; set; }
}
Controller
public ActionResult EmployeeData() {
EmployeeViewModel model = new EmployeeViewModel();
EmployeeDepartment ed = new EmployeeDepartment();
model.Id = 1;
model.Name = "Muhammmad Ashraf Faheem";
model.Email = "it.ashraffaheem#gmail.com";
ed.Id = 1;
ed.DepartmentName = "Development";
model.employeeDepartment = ed;
return View(model);
}
View
#model UploadFileDemo.Models.EmployeeViewModel
#{ViewBag.Title = "EmployeeData";}
<label>#Model.Id</label><br />
<label>#Model.Name</label><br />
<label>#Model.Email</label><br />
<label>#Model.employeeDepartment.Id</label><br />
<label>#Model.employeeDepartment.DepartmentName</label>
with this way we can use parent and child model in same view :

How do I extract an ID, select the correct view model from a list and pass this inside a partial?

I'm fairly new to MVC.
I have the following scenario: I have a list of quotes on a QuoteDetails page. I click on a quote and it takes me through an ItemDetails page where I can view a list of associated items.
An item belongs to a quote and a quote can have many items. These items are listed on a sidebar on ItemDetails page.
#model QuotePageViewModel
<div class="list-group">
#{bool firstItem = true;}
#foreach (var quote in Model.LiveQuotes)
{
if (firstItem.Equals(true))
{
firstItem = false;
<a href="#" id="#quote.Item.ItemID" class="list-group-item active">
<span class="glyphicon glyphicon-file"></span>#quote.Item.Title<span class="badge">ItemID: #quote.Item.ItemID</span>
</a>
}
else
{
<a href="#" id="#quote.Item.ItemID" class="list-group-item">
<span class="glyphicon glyphicon-file"></span>#quote.Item.Title<span class="badge">ItemID: #quote.Item.ItemID</span>
</a>
}
}
</div>
<div class="col-sm-9">
#Html.Partial(MVC.Item.Views.ViewNames._TabbedItemDetailsPanel, ViewData)
</div>
This lists all my items as expected.
When I select an item, I want to grab the correct ItemViewModel in my partial. What would be the best way to do this?
I have a few ideas but I'm not quite sure how to accomplish them. For example, one is:
The class that is active, grab the Item ID use linq to filter LiveQuotes and select the QuotesOverviewViewModel pass this into the partial.
Or would an ajax call be better suited for this?
I have a QuotePageViewModel that looks like this:
public class QuotePageViewModel : PageViewModel
{
public IEnumerable<QuotesOverviewViewModel> LiveQuotes { get; set; }
}
public class QuotesOverviewViewModel : DataViewModel
{
public QuoteViewModel Quote { get; set; }
public CustomerViewModel Customer { get; set; }
public QuoteStatusViewModel QuoteStatus { get; set; }
public OriginatorViewModel Originator { get; set; }
public ItemViewModel Item { get; set; }
}
public class ItemViewModel : DataViewModel
{
public int ItemID { get; set; }
public int? QuoteID { get; set; }
public string Title { get; set; }
public int? Quantity { get; set; }
public Money Price { get; set; }
public QuoteViewModel Quote { get; set;}
}
Hope that's clear. Please ask if you don't understand. Thanks
It seems I was looking at it the wrong way around.
The following worked out for me.
I extended the QuotePageViewModel
public class QuotePageViewModel : PageViewModel
{
public IEnumerable<QuotesOverviewViewModel> LiveQuotes { get; set; }
public PaginatedViewModel<QuotesOverviewViewModel> ArchivedQuotes { get; set; }
public ItemViewModel SelectedItem { get; set; }
}
I set the value in my ViewModelService. On page load I added this:
<a href="#Url.Action(MVC.Item.ActionNames.ItemDetail, MVC.Item.Name, new { itemId = #quote.Item.ItemID })" id="#quote.Item.ItemID" class="list-group-item active">
Updated the partial:
#Html.Partial(MVC.Item.Views.ViewNames._TabbedItemDetailsPanel, Model.SelectedItem)
Hope this helps someone.

Asp.net two models in one view

I'm trying to get 2 models to show in 1 view but it is not working. I have tried lots of different ideas from Google but none have worked so far.
There is no error in the Error List. But when I start it I get this error.
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Namespace.Models.Class1]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Namespace.Models.ParentClass]'.
I have a parent class containing the to child classes. If i use the #model IEnumerable<> directly at the child class it works, but not when pointed at the parent.
What am I doing wrong?
EDIT
Ok so these are my files.
Model1.cs
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
Model2.cs
public int AnotherProperty1 { get; set; }
public int AnotherProperty2 { get; set; }
ViewModel.cs
public IEnumerable<Model1> Model1 { get; set; }
public IEnumerable<Model2> Model2 { get; set; }
HomeController.cs
private ConnectContext db = new ConnectContext();
public ActionResult Index()
{
var model = from m in db.model select m;
model = db.model.OrderByDescending(m => m.ID);
return View(db.model.ToList());
}
Index.chstml
#model IEnumerable<Namespace.Models.ViewModel>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Model1.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Model2.Title)
</td>
</tr>
}
Now with the files like this my error message is
CS1061: 'System.Collections.Generic.IEnumerable<Namespace.Models.Model1>' does not contain a definition for 'Cover' and no extension method 'Cover' accepting a first argument of type 'System.Collections.Generic.IEnumerable<Namespace.Models.Model1>' could be found (are you missing a using directive or an assembly reference?)
If you have two and only two classes you want to pass in, have you considered using a tuple?
For example:
On the controller end,
var model = new Tuple<ModelType1, ModelType2>(yourModel1, yourModel2);
return View(model);
On the view end, you'll want this at the top, along with any using statements you may need:
#model Tuple<ModelType1, ModelType2>
To access each part in the view, #Model.Item1 will be your ModelType1 and #Model.Item2 will be your ModelType2.
If you wind up with more than two classes, it might be a good idea for you to make a ViewModel class with properties for the various types you want to include. (You can also cop out and add properties to the ViewBag.)
What about just making a model class with properties that makes up the two classes you need for your view?
E.g.
public class FirstModel
{
public int Id { get; set; }
public string SomeProperty { get; set; }
}
public class SecondModel
{
public int Id { get; set; }
public string SomeOtherProperty { get; set; }
}
public class ViewModel
{
public FirstModel MyFirstModel { get; set; }
public SecondModel MySecondModel { get; set; }
}
Then in your view you use a model of ViewModel.
Try this:
public class FirstModel
{
public int Id { get; set; }
public string SomeProperty { get; set; }
}
public class SecondModel
{
public int Id { get; set; }
public string SomeOtherProperty { get; set; }
}
public class ViewModel
{
public FirstModel MyFirstModel { get; set; }
public SecondModel MySecondModel { get; set; }
}
In your Controller:
private ConnectContext db = new ConnectContext();
public ActionResult Index()
{
FirstModel firstModel = //Set FirstModel Value;
SecondModel secondModel = //Set SecondModel Value;
ViewModel viewModel = new ViewModel(){
FirstModel = firstModel,
SecondModel = secondModel
}
return View(viewModel);
}
Finally I got this working. I had to change my ViewModel, Controller and View.
ViewModel.cs (From IEnumerable to List)
public List<Model1> Model1 { get; set; }
public List<Model2> Model2 { get; set; }
HomeController.cs
private ConnectContext db = new ConnectContext();
public ActionResult Index()
{
ViewModel vm = new ViewModel();
vm.Model1 = (from m in db.Model1 select m).OrderByDescending(x => x.ID).Take(3).ToList();
vm.Model2 = (from t in db.Model2 select t).OrderByDescending(x => x.ID).Take(3).ToList();
return View(vm);
}
Index.cshtml
(So here I removed the IEnumerable and then each Foreach connects to each Model)
#model Namespace.Models.ViewModel
#foreach (var item in Model.Model1) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
</tr>
}
#foreach (var item in Model.Model2) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
</tr>
}

How to display create form in an existing MVC 4 view and C#

I have view to display Restaurant. In this view at the bottom of the page, I want to display Comments form to add comments about that Restaurant.
Can someone please help me to do this using MVC 4 & C#.
My Models has the followign two tables:
/Classifieds TABLE
public class Classifieds
{
[Key]
public string C_Unique_Id { get; set; }
public string AdType { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
//ClassifiedsComments TABLE
public class ClassifiedsComments
{
[Key]
public string CCommentsUniqueId { get; set; }
public string CommentAuthor { get; set; }
public string Comment { get; set; }
[ForeignKey("Classifieds")]
public string C_Unique_Id { get; set; } //this is the foreign key of Classified record
public virtual Classifieds Classifieds { get; set; }
}
Classifieds Details view:
#model SomeIndianShit.Models.Classifieds
#{
ViewBag.Title = "Details";
}
<table class="recordDetailsDisplayTableStype">
<tr>
<td colspan="2" align="left">
#Html.DisplayFor(model => model.Description)
<br /><br />
</td>
</tr>
<tr>
<td>
Ad Type
</td>
<td align="left"> :
#Html.DisplayFor(model => model.AdType)
</td>
</tr>
SOME OTHER FIELDS DISPLAY HERE
</table>
//Here I want to display "ClassifiedsComments" form to add comments to above Classified.
//HOW can I display the ClassifiedsComments create.cshtml code here??
Try this:
With View:
#using (Html.BeginForm("Classifieds", "ClassifiedsDetails", FormMethod.Post))
and
#using (Html.BeginForm("ClassifiedsComments", "ClassifiedsDetails", FormMethod.Post))
And use 1 Model for this:
public class ClassifiedsDetails
{
public Classifieds Model1{ get; set; }
public ClassifiedsComments Model2{ get; set; }
}
Update:
public class ClassifiedsDetails
{
public ClassifiedsDetails()
{
Model1 = new Classifieds();
Model2 = new ClassifiedsComments();
}
public Classifieds Model1{ get; set; }
public ClassifiedsComments Model2{ get; set; }
}
public class Classifieds
{
public Classifieds()
{
C_Unique_Id = String.Emty;
AdType = String.Emty;
//---- Add default setting here------
}
[Key]
public string C_Unique_Id { get; set; }
public string AdType { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
Or display list of comments in View with Model:
public class ClassifiedsDetails
{
public ClassifiedsDetails()
{
Model1 = new Classifieds();
Model2 = new List<ClassifiedsComments>();
}
public Classifieds Model1{ get; set; }
public List<ClassifiedsComments> Model2{ get; set; }
}
View:
#model ClassifiedsDetails
#Html.LabelFor(model => model.Model1.Title)
#foreach (var items in Model.Model2)
{
#item. //fields
}
To display data in view create view model, but to post comment, dont use model:
public class ClassifiedsViewModel
{
public ClassifiedsViewModel()
{
Comments = new List<ClassifiedsComments>();
}
public Classifieds Classifieds { get; set; }
public List<ClassifiedsComments> Comments { get; set; }
}
Fill this view model, use in view to display details and comments like above you write.
if(Model != null && Model.Classifieds != null)
{
<table> ...display details.. </table>
}
if(Model != null && Model.Comments != null)
{
<table> ...display comments with foreach loop.. </table>
}
And at bottom, create comment post form
#using (Html.BeginForm("SaveComment", "Controller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
//set to which Classifieds will this comment posted
#Html.Hidden("C_Unique_Id", Model.Classifieds.C_Unique_Id)
<fieldset>
#Html.TextBox("Comment")
//other fields ....
<input type="submit" value="Save" />
</fieldset>
}
Edit2: View model creating:
public ActionResult Details(int id)
{
//add breakpoint here and follow any step.
ClassifiedsViewModel viewModel = new ClassifiedsViewModel();
viewModel.Classifieds = db.Classifieds.Find(id);
viewModel.Comments = db.LoadCommentsByClassifiedsId(id); //create db method
// or instead of this line use:
viewModel.Comments = db.ClassifiedsComments.Where(e => e.C_Unique_Id == id).ToList();
return(viewModel);
}
You can then add a ViewModel like this
public class ClassifiedsDetailViewModel
{
public ClassifiedsDetailViewModel()
{
ClassifiedsComments = new ClassifiedsComments();
}
public Classifieds Classifieds { get; set; }
public ClassifiedsComments ClassifiedsComments { get; set; }
}
Pass this view model to your view and then add #Html.Partial("_CreateClassifiedsCommentsFormPartial", Model.ClassifiedComments) below the table. And in your partial view, you can use Html.BeginForm or the Ajax.BeginForm.
See sample here

Categories

Resources