Join two Model classes result and display it on View-MVC - asp.net-mvc

I want to combine below two classes result using Linq and display the result on a view?
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("ProductMaster")]
public partial class ProductMaster
{
public ProductMaster()
{
ProductDetails = new HashSet<ProductDetail>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ProductId { get; set; }
[StringLength(50)]
public string ProductName { get; set; }
public virtual ICollection<ProductDetail> ProductDetails { get; set; }
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class ProductDetail
{
public int? Price { get; set; }
[StringLength(50)]
public string ManufactureBy { get; set; }
public int? ProductId { get; set; }
[Key]
public int ProdDetailsId { get; set; }
public virtual ProductMaster ProductMaster { get; set; }
}
Join two tables data using LINQ Query.
public ActionResult BindProductMasterData()
{
Model1 db = new Model1();
var varResult = from pm in db.ProductMasters join pd in db.ProductDetails on pm.ProductId equals pd.ProductId select new { pm.ProductId, pm.ProductName, pd.Price, pd.ManufactureBy };
return View(varResult.ToList());
}
Display below table columns data in View
ProductId , ProductName, Price, ManufactureBy

Create a view model for this view and assign your LINQ join query result to a list of that and pass that to the view.
public class ProductVm
{
public int Id { set;get;}
public string Name { set;get;}
public List<ProductDetailVm> Details { set;get;}
}
public class ProductDetailVm
{
public int Id { set;get;}
public int? Price { get; set; }
public string ManufactureBy { get; set; }
}
and in your action method, project the result of your LINQ query to a list of ProductVm objects.
public ActionResult BindProductMasterData()
{
Model1 db = new Model1();
var varResult = db.ProductMasters
.Select( f =>
new ProductVm
{
Id = f.ProductId,
Name = f.ProductName,
Details = f.ProductDetails.Select(g => new ProductDetailVm
{
Id = g.ProdDetailsId ,
Price = g.Price,
ManufactureBy = g.ManufactureBy
}
).ToList()
}).ToList();
return View(varResult);
}
Now make sure your view is strongly typed to a list of our ProductVm view model
#model List<ProductVm>
#foreach(var p in Model)
{
<h4>#p.ProductName</p>
<p>Details</p>
#foreach(var d in p.Details)
{
<p>#d.ManufacturedBy</p>
<p>#d.Price</p>
}
}

Related

pass multiple data as a list to View in MVC

How to pass LINQ data to View. I have used below code but it throwing conversion error.
namespace WebApplication1.DataContext
{
public class Repositary
{
public ProductMaster productMaster { get; set; }
public ProductDetail productDetail { get; set; }
}
}`
Action Method:-
public ActionResult ProductMasterWithDetails()
{
Model1 db=new Model1();
Repositary rep = new Repositary();
var varResult= from pm in db.ProductMasters join pd in db.ProductDetails on pm.ProductId equals pd.ProductId select new { pm.ProductId, pm.ProductName, pd.Price, pd.ManufactureBy };
ViewBag.result = varResult.ToList();
return View();
}
Error: Cannot initialize type 'WebApplication1.DataContext.Repositary'
with a collection initializer because it does not implement
'System.Collections.IEnumerable'
C:\Users\msnsh\onedrive\documents\visual studio
2013\Projects\WebApplication1\WebApplication1\Controllers\ProductController.cs 55 141 WebApplication1
In View:
#foreach (var result in ViewBag.result){
}
I have two model classes as follows.
namespace WebApplication1.DataContext
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("ProductMaster")]
public partial class ProductMaster
{
public ProductMaster()
{
ProductDetails = new HashSet<ProductDetail>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ProductId { get; set; }
[StringLength(50)]
public string ProductName { get; set; }
public virtual ICollection<ProductDetail> ProductDetails { get; set; }
}
}
namespace WebApplication1.DataContext
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class ProductDetail
{
public int? Price { get; set; }
[StringLength(50)]
public string ManufactureBy { get; set; }
public int? ProductId { get; set; }
[Key]
public int ProdDetailsId { get; set; }
public virtual ProductMaster ProductMaster { get; set; }
}
}
If we have two model classes then how to replace below single Model namespace ?
#model IEnumerable
I cannot create a single class as below, because my model has two classes,
public Class ProductCustomModel
{
public int ProductId { get; set; }
public int ProductName { get; set; }
public int Price { get; set; }
public int ManufactureBy { get; set; }
}
Here is my Model1 Class.
namespace WebApplication1.DataContext
{
using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Data.Entity.Spatial;
public partial class Model1 : DbContext
{
public Model1()
: base("name=Model1")
{
}
public virtual DbSet<ProductDetail> ProductDetails { get; set; }
public virtual DbSet<ProductMaster> ProductMasters { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ProductDetail>()
.Property(e => e.ManufactureBy)
.IsUnicode(false);
modelBuilder.Entity<ProductMaster>()
.Property(e => e.ProductName)
.IsUnicode(false);
}
}
}
If you getdata in varResult than you should try,
In Conroller.
Model1 db=new Model1();
var varResult= (from pm in db.ProductMasters join pd in db.ProductDetails on pm.ProductId equals pd.ProductId select new { pm.ProductId, pm.ProductName, pd.Price, pd.ManufactureBy }).ToList();
return View("path to the view",varResult);
In View
#model ModelName
#foreach (var result in Model){
}
You should need to change the ViewBag to the customModel/Class which will send the List to your view.
Models:
namespace WebApplication1.DataContext
{
public class Repositary
{
public ProductMaster productMaster { get; set; }
public ProductDetail productDetail { get; set; }
}
public Class ProductCustomModel
{
public int ProductId { get; set; }
public int ProductName { get; set; }
public int Price { get; set; }
public int ManufactureBy { get; set; }
}
}
Change your action Method to this:
public ActionResult ProductMasterWithDetails()
{
Model1 db=new Model1();
Repositary rep = new Repositary();
var varResult= from pm in db.ProductMasters join pd in db.ProductDetails on pm.ProductId equals pd.ProductId select new { pm.ProductId, pm.ProductName, pd.Price, pd.ManufactureBy };
//Make your List Here like this and add the values in it.
List<ProductCustomModel> productCustomModelList = new List<ProductCustomModel>();
Foreach(ProductCustomModel item in varResult)
{
ProductCustomModel singleData = new ProductCustomModel();
ProductId = item.ProductId,
ProductName = item.ProductName,
Price = item.Price,
ManufactureBy = item.ManufactureBy
productCustomModelList.Add(singleData);
}
return View(productCustomModelList);
}
In the View(.cshtml)
#model IEnumerable<WebApplication1.DataContext.ProductCustomModel>
#foreach (var result in Model){
//.. operations
}

Requires a model item of type 'System.Collections.Generic.IEnumerable`1

I have a LINQ query in my controller that has a join which selects all records. I'm then passing the ReportCompletionStatus.AsEnumerable() model to my view. But I keep getting the fowlling exceptions..
The model item passed into the dictionary is of type 'System.Data.Entity.Infrastructure.DbQuery`1
but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1
I'm setting the model AsEnumerable() and my view is expecting #model IEnumerable so i'm still not sure why it's complaning...
Controller
var ReportCompletionStatus = from r in db.Report_Completion_Status
join rc in db.Report_Category
on r.Report_Category equals rc.ReportCategoryID
select new
{
r.Report_Num,
rc.ReportCategory,
r.Report_Sub_Category,
r.Report_Name,
r.Report_Owner,
r.Report_Link,
r.Report_Description,
r.Last_Published,
r.Previous_Published,
r.Published_By,
r.Previous_Published_By,
r.Last_Edited,
r.Edited_By
};
return View(ReportCompletionStatus.AsEnumerable());
Model
#model IEnumerable<WebReportingTool.Report_Completion_Status>
With your select new, you project to an anonymous type, not to an IEnumerable<WebReportingTool.Report_Completion_Status>
You need to create a ViewModel class (as your projection has data from both Report_Completion_Status and Report_Category) and use it for projection and for your View's model.
class
public class SomeViewModel {
public int ReportNum {get;set;}
public string ReportCategory {get;set;
//etc.
}
projection
select new SomeViewModel
{
ReportNum = r.Report_Num,
ReportCategory = rc.ReportCategory,
//etc.
};
view
#model IEnumerable<SomeViewModel>
By the way, the AsEnumerable is not necessary.
Here's how I got it to work.
Model
public class ReportCategoryListModel
{
public int Report_Num { get; set; }
public string ReportCategory { get; set; }
public string Report_Sub_Category { get; set; }
public string Report_Name { get; set; }
public string Report_Owner { get; set; }
public string Report_Link { get; set; }
public string Report_Description { get; set; }
public Nullable<System.DateTime> Last_Published { get; set; }
public Nullable<System.DateTime> Previous_Published { get; set; }
public Nullable<int> Published_By { get; set; }
public Nullable<int> Previous_Published_By { get; set; }
public Nullable<System.DateTime> Last_Edited { get; set; }
public Nullable<int> Edited_By { get; set; }
}
Controller
var ReportCompletionStatus = from r in db.Report_Completion_Status
join rc in db.Report_Category
on r.Report_Category equals rc.ReportCategoryID
select new ReportCategoryListModel
{
Report_Num = r.Report_Num,
ReportCategory = rc.ReportCategory,
Report_Sub_Category = r.Report_Sub_Category,
Report_Name = r.Report_Name,
Report_Owner = r.Report_Owner,
Report_Link = r.Report_Link,
Report_Description = r.Report_Description,
Last_Published = r.Last_Published,
Previous_Published= r.Previous_Published,
Published_By = r.Published_By,
Previous_Published_By = r.Previous_Published_By,
Last_Edited = r.Last_Edited,
Edited_By = r.Edited_By
};
return View(ReportCompletionStatus);
View
#model IEnumerable<WebReportingTool.Models.ReportCategoryListModel>

How do I pass column values from multiple tables to the view in MVC?

I'm displaying the data from a table called gigs, however it contains a couple of foreign keys to tables 'Bands' and 'Venues' so when using this code in my controller,
string user = User.Identity.GetUserId();
var yourgigs = (from g in dbg.gigs
from v in dbg.Venues
from b in dbg.Bands
from ga in g.gigsaccasses
where (ga.Id == user &&
v.venueid == g.venueid &&
b.bandid == g.bandid)
select g);
return View(yourgigs);
it's displaying bandid and venueid in the view which are meaningless integers. How would I replace those with what I suppose would be b.bandname, v.venuename and also add v.address1 and v.city? The SQL statement that does this is
SELECT bands.bandname, venues.venuename, venues.address1, venues.city, gigs.whatdate, gigs.starttime
FROM gigs INNER JOIN
bands ON gigs.bandid = bands.bandid INNER JOIN
gigsaccass ON gigs.gigid = gigsaccass.gigid INNER JOIN
dbo.AspNetUsers ON gigsaccass.Id = dbo.AspNetUsers.Id INNER JOIN
venues ON gigs.venueid = venues.venueid
WHERE dbo.AspNetUsers.Id = //some user//
I did try using anonymous types as such:
var yourgigs = (from g in dbg.gigs
from v in dbg.Venues
from b in dbg.Bands
from ga in g.gigsaccasses
where (ga.Id == user &&
v.venueid == g.venueid &&
b.bandid == g.bandid
select new
{
bandname = b.bandname,
venuename = v.venuename,
address1 = v.address1,
city = v.city,
whatdate = g.whatdate,
starttime = g.starttime
});
But this then threw an error:
The model item passed into the dictionary is of type 'System.Data.Entity.Infrastructure.DbQuery1[<>f__AnonymousType76[System.String,System.String,System.String,System.String,System.DateTime,System.TimeSpan]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[OnStageTonight_MVC.Models2.gigs]'.
The View is expecting type 'gigs'
#model IEnumerable<OnStageTonight_MVC.Models2.gigs>
#{
ViewBag.Title = "Gigs";
}
<h2>Gigs</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.venueid)
</th>
<th>
#Html.DisplayNameFor(model => model.bandid)
</th>
What am I missing?
EDIT:
I should add that I do have a model, but I'm assuming this is what is at fault.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace OnStageTonight_MVC.Models2
{
[Table("gigs")]
public partial class gigs
{
public gigs()
{
this.gigsaccasses = new HashSet<gigsaccass>();
}
[Key]
public int gigid { get; set; }
public int venueid { get; set; }
public int bandid { get; set; }
[Display(Name="Date")]
public System.DateTime whatdate { get; set; }
[Display(Name="Starts at")]
public System.TimeSpan starttime { get; set; }
public virtual ICollection<gigsaccass> gigsaccasses { get; set; }
}
[Table("gigsaccass")]
public partial class gigsaccass
{
[Key]
public int gigaccassid { get; set; }
public int gigid { get; set; }
public string Id { get; set; }
public virtual gigs gig { get; set; }
public virtual AspNetUsers AspNetUser { get; set; }
}
[Table("dbo.AspNetUsers")]
public class AspNetUsers
{
[Key]
public string Id { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public Nullable<System.DateTime> LockoutEndDateUtc { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public string UserName { get; set; }
public string YourName { get; set; }
public List<gigsaccass> gigsaccasses { get; set; }
}
[Table("venues")]
public partial class venues
{
[Key]
public int venueid { get; set; }
[Required]
[Display(Name = "Venue")]
public string venuename { get; set; }
[Required]
[Display(Name = "Address")]
public string address1 { get; set; }
[Required]
[Display(Name = "City")]
public string city { get; set; }
public List<gigs> venuegigs { get; set; }
}
[Table("bands")]
public class bands
{
[Key]
public int bandid { get; set; }
[Required]
[Display(Name = "Name")]
public string bandname { get; set; }
public List<gigs> bandgigs { get; set; }
}
public partial class gigscontext : DbContext
{
public gigscontext()
: base("DefaultConnection")
{
}
public DbSet<gigs> gigs { get; set; }
public DbSet<gigsaccass> gigsaccass { get; set; }
public DbSet<AspNetUsers> AspNetUsers { get; set; }
public DbSet<venues> Venues { get; set; }
public DbSet<bands> Bands { get; set; }
}
}
You can't use anonymous classes here. Your view needs to know how to work with model, it needs type information, but: "The type name is generated by the compiler and is not available at the source code level"
You can't pass such objects around. http://www.codeproject.com/Articles/15624/Inside-C-Anonymous-Methods#5
You need to create class that represent row in your data set and return list of populated objects.
As less preferred alternative you can use dynamic: https://msdn.microsoft.com/en-us/library/dd264736.aspx
The M in MVC stands for model, and what you want is one of the 3 main tenants of MVC.
You want an object that encapsulates all the information to be displayed on the view.
It is considered best practice to create a model for the view. This is an additional layer which separates the storage of the item (your entity model) from it's presentation.
var yourgigs = (from g in dbg.gigs
from v in dbg.Venues
from b in dbg.Bands
from ga in g.gigsaccasses
where (ga.Id == user &&
v.venueid == g.venueid &&
b.bandid == g.bandid
select new GigViewModel
{
bandname = b.bandname,
venuename = v.venuename,
address1 = v.address1,
city = v.city,
whatdate = g.whatdate,
starttime = g.starttime
});
public class GigViewModel
{
public string bandname { get; set; }
public string venuename { get; set; }
public string address1 { get; set; }
public string city { get; set; }
public DateTime whatdate { get; set; }
public Timespan starttime { get; set; }
}
When persisting data from your view models, use AutoMapper or something similar to copy properties with matching names between your view models and your entity models.
Use the new view model in your view:
#model IEnumerable<OnStageTonight_MVC.Models2.GigModelView>

How to design a ViewModel for a todo list application?

I am creating a simple todo application which has two entities, tasks and categories.
To create a task, choosing a category is a must. For this, I figured I would need a ViewModel.
Here is the Task entity
public class Task
{
public int taskId { get; set; }
public int categoryId { get; set; }
public string taskName { get; set; }
public bool isCompleted { get; set; }
public DateTime creationDate { get; set; }
public DateTime completionDate { get; set; }
public string remarks { get; set; }
public string completionRemarks { get; set; }
}
Here is the Category entity
public class Category
{
public int categoryId { get; set; }
public string categoryName { get; set; }
}
How can I design a TaskCategoryViewModel so that I can bind the category in the CreateTask view?
Edit: I am using classic ADO.NET instead of Entity Framework or LINQ to SQL.
Kishor,
the best bet is have model that hods definition for your task and for category (all in one)
here is how everything hangs together.
where
IEnumerable<SelectListItem> Categories
is used for creating drop down list which is ready to use
<%= Html.DropDownListFor(model=>model.NewTask.categoryId, Model.Categories) %>
this will create you nice dropdown list
private IEnumerable<Category> GetCategories
{
get
{
List<Category> categories = new List<Category>
{
new Category() {categoryId = 1, categoryName = "test1"},
new Category() {categoryId = 2, categoryName = "category2"}
};
return categories;
}
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult CreateTask()
{
TaskModel taskModel = new TaskModel();
LoadCategoriesForModel(taskModel);
return View(taskModel);
}
private void LoadCategoriesForModel(TaskModel taskModel)
{
taskModel.Categories =
GetCategories.Select(
x =>
new SelectListItem()
{Text = x.categoryName, Value = x.categoryId.ToString(CultureInfo.InvariantCulture)});
}
public ActionResult CreateTask(TaskModel taskModel)
{
if (ModelState.IsValid)
{
// do your logic for saving
return RedirectToAction("Index");
}
else
{
LoadCategoriesForModel(taskModel);
return View(taskModel);
}
}
/// <summary>
/// your model for creation
/// </summary>
public class TaskModel
{
public Task NewTask { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
/// <summary>
/// Task
/// </summary>
public class Task
{
public int taskId { get; set; }
public int categoryId { get; set; }
public string taskName { get; set; }
public bool isCompleted { get; set; }
public DateTime creationDate { get; set; }
public DateTime completionDate { get; set; }
public string remarks { get; set; }
public string completionRemarks { get; set; }
}
/// <summary>
/// Category
/// </summary>
public class Category
{
public int categoryId { get; set; }
public string categoryName { get; set; }
}
In the TaskViewModel (I would prefer naming it CreateTaskViewModel) create property for categories select list
public IEnumerable<SelectListItem> CategoriesSelectList;
In controller, bind that property before returning view (note that this also should be done in post handler, when ModelState is invalid)
public ViewResult Create()
{
CreateTaskViewModel model = new CreateTaskViewModel();
model.CategoriesSelectList = _repository.AllCategories().Select(x=> new SelectListItem(){ Text = x.CategoryName, Value = x.CategoryId.ToString();}
}
And finally, in the view
Html.DropDownListFor(model => model.CategoryId, Model.CategoriesSelectList)
Edit:
In your code, _repository.AllCategories() should be replaced by your data access code, that returns object having type IEnumerable<Category>. It actually does not matter which data access technology you use. And do not forget to add the using System.Linq; statement to your controller file, if it's missing.

Linq to Entity | Pass table join to model

Good time of a day!
I have a MVC project with query in controller:
var getPhotos = (from m in db.photos
join n in db.comments on m.id equals n.photoid
where n.ownerName == User.Identity.Name
orderby n.id descending
select new {
m.imgcrop, m.id,
n.commenterName, n.comment
}).Take(10);
How to pass this query to view model, and the model to view.
Spend all evening to find the examples, but cant. Thanks for help!
UPDATED
Full Model Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace photostorage.Models
{
public class GlobalModel
{
public class PhotoViewModel
{
public photos Photos { get; set; }
public profiles Profile { get; set; }
public IQueryable<comments> Comments { get; set; }
public IQueryable<photos> NextPrev { get; set; }
}
public class UserPhotoList
{
public IQueryable<photos> Photos { get; set; }
public profiles Profile { get; set; }
}
public class UserProfileView
{
public IQueryable<photos> Photos { get; set; }
public profiles Profile { get; set; }
}
public class GetLastComments
{
public IQueryable<photos> uPhoto { get; set; }
public IQueryable<comments> uComments { get; set; }
}
}
}
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using photostorage.Models;
namespace photostorage.Controllers
{
public class HomeController : Controller
{
private photostorageEntities db = new photostorageEntities();
public ActionResult Index()
{
if(Request.IsAuthenticated) {
GlobalModel.GetLastComments model = new GlobalModel.GetLastComments();
var getPhotos = (from m in db.photos
join n in db.comments on m.id equals n.photoid
where n.ownerName == User.Identity.Name
select new {
m.imgcrop, m.id,
n.commenterName, n.comment
}).Take(10);
return View("Index_Auth", model);
}else{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View("Index");
}
}
public ActionResult About()
{
return View();
}
}
}
In this case you can make a "view model" that will only be used by your view and not by the rest of your application. Something like the following:
public class CommentsViewModel
{
public int MessageId { get; set; }
public string ImageCrop { get; set; }
public string CommenterName { get; set; }
public string Comment { get; set; }
}
Then change your query like so:
var getPhotos = (from m in db.photos
join n in db.comments on m.id equals n.photoid
where n.ownerName == User.Identity.Name
orderby n.id descending
select new CommentsViewModel {
ImageCrop = m.imgcrop,
MessageId = m.id,
CommenterName = n.commenterName,
Comment = n.comment
}).Take(10).ToList();
Make your view strongly typed to the new class and pass the data to it like so:
View("name_of_your_view", getPhotos);
If you wanted to do this, like you had:
var getPhotos = (from m in db.photos
join n in db.comments on m.id equals n.photoid
where n.ownerName == User.Identity.Name
select new {
m.imgcrop, m.id,
n.commenterName, n.comment
}).Take(10);
You could actually have this without creating a new "CommentsViewModel", but just use what should be the existing tables and models:
var getPhotos = (from m in db.Photos
join n in db.Comments on m.Id equals n.PhotoId
where n.OwnerName == User.Identity.Name
select new {
ImageCrop = m.ImageCrop,
Id = m.Id,
CommenterName = n.CommenterName,
Comment = n.Comment
}).Take(10);
The models would be something like these examples, if you had a foreign key relationship on the Photo.Id to Comments.PhotoId:
public class Photos
{
public int Id { get; set; }
public string ImageCrop { get; set; }
[ForeignKey("PhotoId")]
public virtual Comments Comment { get; set; }
}
public class Comments
{
public int Id { get; set; }
public int PhotoId { get; set; }
public string CommenterName { get; set; }
public string OwnerName { get; set; }
public string Comment { get; set; }
}
Just a note: The models you displayed in your question had none of these columns, yet you were building a query against them. It's best to remember to give a complete picture when asking for help.

Resources