pass multiple data as a list to View in MVC - asp.net-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
}

Related

Using Views like tables in Entity Framework Code-first Existing database approach

I currently have a working WPF project that is using 2 tables from a sample Northwind database. Using Entity Framework code-first from an existing database these tables are displayed in master-detail format. I would like to use two views instead of the two tables.
I have found several tutorials and have implemented accordingly but for some reason I cannot get the dbcontext to read from the views. I created two views each matching the tables. I modified the class for the view to use [Table("vView")] and assigned a [Key] to create a primary key on the view but still no success. All research shows is to treat the view as if it was a table and all code should be the same. I am using Products and Categories table from Northwind database to test. I created their corresponding views vProducts and vCategories in the Northwind database.
Here is the code that works using the tables Products and Categories generated from the Entity Data Model (code-first):
Category.cs
namespace WPFCodeFirstExisting
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Category
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Category()
{
Products = new HashSet<Product>();
}
public int CategoryID { get; set; }
[Required]
[StringLength(15)]
public string CategoryName { get; set; }
[Column(TypeName = "ntext")]
public string Description { get; set; }
[Column(TypeName = "image")]
public byte[] Picture { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Product> Products { get; set; }
}
}
Products.cs
namespace WPFCodeFirstExisting
{
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Product
{
public int ProductID { get; set; }
[Required]
[StringLength(40)]
public string ProductName { get; set; }
public int? SupplierID { get; set; }
public int? CategoryID { get; set; }
[StringLength(20)]
public string QuantityPerUnit { get; set; }
[Column(TypeName = "money")]
public decimal? UnitPrice { get; set; }
public short? UnitsInStock { get; set; }
public short? UnitsOnOrder { get; set; }
public short? ReorderLevel { get; set; }
public bool Discontinued { get; set; }
public virtual Category Category { get; set; }
}
}
ProductContext.cs
namespace WPFCodeFirstExisting
{
using System.Data.Entity;
public partial class ProductContext : DbContext
{
public ProductContext()
: base("name=ProductContext")
{
Database.SetInitializer<ProductContext>(null);
}
public virtual DbSet<Category> Categories { get; set; }
public virtual DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.Property(e => e.UnitPrice)
.HasPrecision(19, 4);
}
}
}
MainWindows.xaml.cs
public partial class MainWindow : Window
{
public ProductContext _context = new ProductContext();
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
System.Windows.Data.CollectionViewSource categoriesViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("categoriesViewSource")));
_context.Categories.Where(x => x.CategoryName.Contains("P")).Load();
categoriesViewSource.Source = _context.Categories.Local;
}
App.config:
<connectionStrings>
<add name="ProductContext" connectionString="data source=ABC;initial catalog=Northwind;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
<add name="ProductContextView" connectionString="data source=ABC;initial catalog=Northwind;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>
Now if I modify the code to use 2 views instead:
SELECT * FROM [dbo].[vProducts]
SELECT * from [dbo].[vCategories]
these views just contain the select statement from their respective tables.
vCategory.cs:
namespace WPFCodeFirstExisting
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("vCategories")]
public class vCategory
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public vCategory()
{
vProducts = new HashSet<vProduct>();
}
[Key]
public int CategoryID { get; set; }
[StringLength(15)]
public string CategoryName { get; set; }
[Column(TypeName = "ntext")]
public string Description { get; set; }
[Column(TypeName = "image")]
public byte[] Picture { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<vProduct> vProducts { get; set; }
}
}
vProducts.cs:
namespace WPFCodeFirstExisting
{
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("vProducts")]
public class vProduct
{
[Key]
public int ProductID { get; set; }
[Required]
[StringLength(40)]
public string ProductName { get; set; }
public int? SupplierID { get; set; }
[ForeignKey("CategoryID")]
public int? CategoryID { get; set; }
[StringLength(20)]
public string QuantityPerUnit { get; set; }
[Column(TypeName = "money")]
public decimal? UnitPrice { get; set; }
public short? UnitsInStock { get; set; }
public short? UnitsOnOrder { get; set; }
public short? ReorderLevel { get; set; }
public bool Discontinued { get; set; }
public virtual vCategory vCategory { get; set; }
}
}
ProductContextView.cs
namespace WPFCodeFirstExisting
{
using System.Data.Entity;
public class ProductContextView : DbContext
{
public ProductContextView()
: base("name=ProductContextView")
{
Database.SetInitializer<ProductContextView>(null);
}
public DbSet<vCategory> vCategories { get; set; }
public DbSet<vProduct> vProducts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<vProduct>()
.Property(e => e.UnitPrice)
.HasPrecision(19, 4);
}
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public ProductContextView _context = new ProductContextView();
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
System.Windows.Data.CollectionViewSource categoriesViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("categoriesViewSource")));
_context.vCategories.Where(x => x.CategoryName.Contains("P")).Load();
categoriesViewSource.Source = _context.vCategories.Local;
}
When I run using the ProductContextView, These lines do not return any data;
_context.vCategories.Where(x => x.CategoryName.Contains("P")).Load();
categoriesViewSource.Source = _context.vCategories.Local;
I even tried doing something very simple like the following:
var prods = _context.Database.SqlQuery<vCategory>("Select * from dbo.vCategories");
foreach (var p in prods)
{
string test = p.CategoryName.ToString();
}
but prods doesn't return any data either. This test works perfectly fine when using the tables.
I'm hoping to just replace the tables with views using EF. I do not want to use any CRUD operations with the views they are fine being read-only.
What I found is that in code-first if you add a class representing a view as dbSet when the database is seeded it will create what you want to be a view as a table (probably why you are getting no results).
A work around is to create a custom an initializer :
public class CustomDBInitializer : CreateDatabaseIfNotExists<ProductContextView>
{
protected override void Seed(ProductContextView context)
{
base.Seed(context);
}
}
Then after the base seed method use...
context.Database.ExecuteSqlCommand()
...to drop the generated tables and run a SQL script that generates the views to replace them.
You can then use the dbset like a table but it will actually be using the view.
Also not sure why you created to separate contexts.

Dictionary requires a model item of type IEnumerable

I'm new to MVC with Linq and in my project, I am getting an error:
The model item passed into the dictionary is of type 'System.Boolean', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Parts.PartsLocation]'.
I am using MVC with EF, so how do I return an IEnumerable?
Here is my Controller:
public async Task<ActionResult> Index(String aContainer)
{
var container = from x in db.PartsLocations select x;
var empty = from y in db.PartsLocations select y;
if (!String.IsNullOrEmpty(aContainer))
{
var parent = from a in db.PartsLocations
where (a.LocationName == aContainer)
select a.ParentLocation;
return View(await parent.ToListAsync());
}
empty = empty.Where(r => r.LocationName.Contains(null));
return View(await empty.ToListAsync());
}
View:
#model IEnumerable<Parts.PartsLocation>
#{
ViewBag.Title = "Index";
}
Model:
namespace Parts
{
using System;
using System.Collections.Generic;
public partial class PartsLocation
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public PartsLocation()
{
this.ManufacturingParts = new HashSet<ManufacturingPart>();
}
public int LocationID { get; set; }
public int TypeID { get; set; }
public string LocationName { get; set; }
public string Description { get; set; }
public int PlantID { get; set; }
public Nullable<int> BayID { get; set; }
public Nullable<int> SecurityGroupID { get; set; }
public Nullable<int> ParentLocation { get; set; }
public Nullable<System.DateTime> LastMoved { get; set; }
public string Notes { get; set; }
public virtual LocationType LocationType { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ManufacturingPart> ManufacturingParts { get; set; }
public virtual ManufacturingPlant ManufacturingPlant { get; set; }
}
}
aContainer Not Null then You have return select
a.ParentLocation
else PartsLocation List
The view model Return Is Difference so Verify The return value

Join two Model classes result and display it on View-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>
}
}

LINQ EF7 ASP.NET and many-to-many

How i could add records to my database , with relation many-to-many in ASP.NET MVC 6 ?
I tried like that, but it's wrong
[HttpPost]
public IActionResult addpersons(Person pers)
{
var ourdoc = db.Documents.FirstOrDefault(p => p.Documentid == docselected);
ourdoc.DocPers.Add(ourdoc);
db.SaveChanges();
return Content("s");
}
Listings of my model files :
DocContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Data.Entity;
namespace TDS_1_ASPNETMVC6.Models
{
public class DocPer
{
public int Documentid { get; set; }
public Document Document { get; set; }
public int Personid { get; set; }
public Person Person { get; set; }
}
public class DocContext : DbContext
{
public virtual DbSet<Document> Documents { get; set; }
public virtual DbSet<Person> Persons { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DocPer>()
.HasKey(t => new
{
t.Documentid,
t.Personid
});
modelBuilder.Entity<DocPer>()
.HasOne(pt => pt.Document)
.WithMany(p => p.DocPers)
.HasForeignKey(pt => pt.Documentid);
modelBuilder.Entity<DocPer>()
.HasOne(pt => pt.Person)
.WithMany(t => t.DocPers)
.HasForeignKey(pt => pt.Personid);
}
}
}
Documents.cs
using System.Collections.Generic;
namespace TDS_1_ASPNETMVC6.Models
{
public class Document
{
public int Documentid { get; set; }
public string Name { get; set; }
public string Props { get; set; }
public List<DocPer> DocPers { get; set; }
}
}
Person.cs
using System.Collections.Generic;
namespace TDS_1_ASPNETMVC6.Models
{
public class Person
{
public int Personid { get; set; }
public string Iname { get; set; }
public string Fname { get; set; }
public string Oname { get; set; }
public string Email { get; set; }
public List<DocPer> DocPers { get; set; }
}
}
First, your controller is not checking for null; what if var ourdoc = db.Documents.FirstOrDefault(p => p.Documentid == docselected); is null? So check for null first :)
Also ourdoc.DocPers.Add(ourdoc); must be changed to ourdoc.DocPers.Add(new DocPer {Person = person});
Second, to create a many-to-many I suggest you to remove the DocPer table and map it "behind", like this:
public class Document
{
public Document()
{
Persons = new List<Person>();
}
public int Documentid { get; set; }
public string Name { get; set; }
public string Props { get; set; }
public virtual ICollection<Person> Persons { get; set; }
}
public class Person
{
public Person()
{
Documents = new List<Document>();
}
public int Personid { get; set; }
public string Iname { get; set; }
public string Fname { get; set; }
public string Oname { get; set; }
public string Email { get; set; }
public virtual ICollection<Document> Documents { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Document>()
.HasMany<Person>(s => s.Persons)
.WithMany(c => c.Documents)
.Map(cs =>
{
cs.MapLeftKey("Documentid");
cs.MapRightKey("Personid");
cs.ToTable("DocPer");
});
}
DocPer table will be managed by the EF without exposing it. Check this site for more details. This guide will apply to EF6 only, not EF7 (which does not support many-to-many yet, for that support check this link). BTW, EF7 is still is not stable yet, so is possibile that this support will be offered in the future, but no one knows yet.

Custom class for query

I have the following query in my Controller
public ActionResult Index(int Id)
{
var People = from a in db.Person
select a;
var Data = from a in db.Member
where a.Person.PersonId.Equals(Id)
select new CustomObject
{
ProjectId = a.Project.ProjectId,
ProjectName = a.Project.Name,
ProjectCustomer = a.Project.Customer,
ProjectTechProfile = a.Project.TechProfile.Select(x => new
{
x.TechId,
x.Name,
x.Elements
}),
MemberId = a.MemberId,
MemberRole = a.Role,
MemberStart = a.Start,
MemberEnd = a.End
};
And I'm making a custom class for my Data query, but I don't know how to set the property of TechProfile
Right now I have this in my custom class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MyProject.Models
{
public class CustomObject
{
public int ProjectId { get; set; }
public string ProjectName { get; set; }
public string ProjectCustomer { get; set; }
public IEnumerable<TechProfile> ProjectTechProfile { get; set; }
public int MemberId { get; set; }
public string MemberRole { get; set; }
public short? MemberStart { get; set; }
public short? MemberEnd { get; set; }
}
}
But the part with
public IEnumerable<TechProfile> ProjectTechProfile { get; set; }
Doesn't work, so do I need to specify TechId, Name and Elements? If so, how?
UPDATE
TechProfile class
namespace MyProject.Models
{
using System;
using System.Collections.Generic;
public partial class TechProfile
{
public int TechId { get; set; }
public string Name { get; set; }
public string Elements { get; set; }
public int ProjectProjectId { get; set; }
public virtual Project Project { get; set; }
}
}
...
ProjectTechProfile = a.Project.TechProfile.Select(x => new TechProfile()
{
TechId = x.TechId,
Name = x.Name,
Elements = x.Elements
},
...

Resources