NullReferenceException was unhandled asp.net entity framework - c#

I'm new to asp.net mvc and I'm doing this exercise for myself.
I created an edmx from Northwind Database.
I created a controller:
public ActionResult Index(int id)
{
var model = new IndexViewModel();
using (var db = new ProductDB())
{
model.Products = from p in db.Products
orderby p.ProductName
select new IndexViewModel.InfoProduct
{
ProductName = p.ProductName,
QuantityPerUnit = p.QuantityPerUnit,
UnitPrice = p.UnitPrice
};
}
return View();
}
...the view:
#model aspTest.Models.IndexViewModel
#{
Layout = null;
}
...
<div> <ul>
#foreach (var p in Model.Products){
<li>#p.ProductName</li>
}
</ul>
</div>
...and the ViewModel:
public class IndexViewModel
{
public IEnumerable<InfoProduct> Products { get; set; }
public class InfoProduct
{
public string ProductName { get; set; }
}
}
But this error keeps on appearing in this part:
#foreach (var p in Model.Products){#p.ProductName
Sorry, I know this might be noobish to most of you.

You are declaring in your model that it will work with the IndexViewModel class as:
#model aspTest.Models.IndexViewModel
but you are sending nothing to the View from Controller as :
return View();
Try using:
return View(model);
The error is quite true, you are trying to iterate on properties (Products) of an object (IndexViewModel) which you don't provide.

Besides the fact that you return no ViewModel to your view and shout use return View(model); there is something else fishy with your code:
public class InfoProduct
{
public string ProductName { get; set; }
}
Your class InfoProduct only contains a Productname, yet you also assign a Quantity and Price property in your select clause, this won't compile.
model.Products = from p in db.Products
orderby p.ProductName
select new IndexViewModel.InfoProduct
{
ProductName = p.ProductName,
};
Lastly, materialize your data using .ToList()
public ActionResult Index(int id)
{
var model = new IndexViewModel();
using (var db = new ProductDB())
{
model.Products = (from p in db.Products
orderby p.ProductName
select new IndexViewModel.InfoProduct
{
ProductName = p.ProductName,
}).ToList();
return View(model);
}
}

Related

Unsuccessful Linq query to retrieve data of composite key table

Hi i would like to write a linq query to retrieve all data of a composite table which is generated as a result of many to many relationship.
This is my query in controller
public ActionResult Index()
{
var act = (from i in _context.act
from j in _context.mvz
where i.Id == j.Id
select i).ToList();
var mvz = _context.mvz.ToList();
var vm = new AAMMViewModel()
{
actz = act
mvz = mvz
};
if (vm == null)
{
return Content("No items found in database");
}
return View(vm);
}
This is view model
public class AAMMViewModel
{
public List<Actors> actz { get; set; }
public List<Movies> mvz { get; set; }
public AAMMViewModel()
{
actz = new List<Actors>();
mvz = new List<Movies>();
}
}
It does not gives the desired result, I know that something is wrong with the logic of my Linq query.
Please guide me if anyone has expertise in this regard.
You can do this:
var act =
(from i in _context.act
where i.Id.SelectMany(id => _context.mvz.Contains(id.Id))
select i).ToList();
Are you sure the ids of Actors and Movies are same. If yes, do the join and use the right property name. You are using act in place of actz in your linq
public class AAMMViewModel
{
public List<Actors> actz { get; set; }
public List<Movies> mvz { get; set; }
public AAMMViewModel()
{
actz = new List<Actors>();
mvz = new List<Movies>();
}
}
var act = (from i in _context.actz
join j in _context.mvz ON i.Id == j.Id
select i).ToList();

Printing output from my linq query in html

I am using asp.net core entity framework. I am trying to print out the results of my query into my html. Here is my code.
This is my .cs file
ViewBag.User_Has_Products = (from user_products in _context.Users_Has_Products
join user in _context.Users on user_products.users_id equals user.id
join product in _context.Products on user_products.products_id equals product.id
select new { name = user.name, product = product.name,
quantity = user_products.quanitity, date = user_products.created_at});
foreach(var item in ViewBag.User_Has_Products)
{
System.Console.WriteLine($"{item.name}"); //this output is correct
}
Here is my .cshtml page
#{
if(ViewBag.User_Has_Products != null)
{
foreach(var item in ViewBag.User_Has_Products)
{
<p>#$"{item.name}"</p> //trying to print it out here
}
}
}
I also tried <p>#item.name</p> but got an object does not contain a definition for name error.
You don't need the string quotes in your .cshtml file, just use it as is, see the following example:
#{
if(ViewBag.User_Has_Products != null)
{
foreach(var item in ViewBag.User_Has_Products)
{
<p>#item.name</p>
}
}
}
But the better recommendation is to build a model and send it to your view, like this:
public class UserProductsViewmodel() {
public string Name { get; set; }
public string Product { get; set; }
public int Quantity { get; set; }
public string Date { get; set;}
}
and use it in your .cs file like this:
ViewBag.User_Has_Products = (from user_products in _context.Users_Has_Products
join user in _context.Users on user_products.users_id equals user.id
join product in _context.Products on user_products.products_id equals product.id
select new UserProductsViewmodel() {
Name = user.name, Product = product.name,
Quantity = user_products.quanitity, Date = user_products.created_at
});
And in your .cshtml like this:
#{
if(ViewBag.User_Has_Products != null)
{
foreach(UserProductsViewmodel item in ViewBag.User_Has_Products)
{
<p>#item.Name</p>
}
}
}
Check this article on Dependency injection into views which will a better way than using ViewBag.
Controller action snippet
public IActionResult GetProducts()
{
var products = (from user_products in _context.Users_Has_Products
join user in _context.Users on user_products.users_id equals user.id
join product in _context.Products on user_products.products_id equals product.id
select new UserProductsViewmodel() {
Name = user.name, Product = product.name,
Quantity = user_products.quanitity, Date = user_products.created_at
});
return View(products);
}
View snippet(.cshtml)
#model IEnumerable<namespace.ProductModel>
...
#foreach (var item in Model)
{
<p>#item.Bar</p>
}
ViewModel
public class ProductModel() {
public string Name { get; set; }
public string Product { get; set; }
public int Quantity { get; set; }
public string Date { get; set;}
}

Bind a Linq Lambda Select Many from Controller to view in MVC4? What are the Best ways to return in view

I am new to MVC by Linq. When I am working with Console application its working fine.
When i shift to Mvc Architecture, passing the values from controller to view i am getting error as
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[<>f__AnonymousType22[System.String,System.String]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[MvcApplication2.Models.Teams]'.
I know i am passing Objects as stringName,String and its expecting 'System.Collections.Generic.IEnumerable how to resolve this kind of issues
This Scenario happen for Multiple groupby and Selectmany in Linq .how to pass the value and get into bind for View . what is the Best approach.
i have put a foreach in Controller and return or else do the foreach iterations in view for selectMany,Groupby,Lookup etc.
Model
public Class Product
{
public string CategoryName {get; set; }
public int Productid { get; set; }
public List<String> Productname { get; set; }
public static List<Product> GetAllProductName()
{
var ListofProducts = new List<Product>
{
new Product { CategoryName = "Choclateid", Productid = 1, Productname = new List<string> { "DairyMilkshots", "DairyMilk Silk", "DairyMilkFruitsNuts" }},
new Product { CategoryName = "Vegetables", Productid = 2, Productname = new List<string> { "Tomoto", "Pototo", "Onion"}},
new Product { CategoryName = "Fruits", Productid = 3, Productname = new List<string> {"Apple", "Orange", "Strawberry"}},
};
return ListofProducts;
}
}
Controller
public ActionResult Home()
{
var ny = Product.GetAllTeamMembers()
.SelectMany(x => x.Productname, (category, withProductlist) =>
new { cat = category.CategoryName, PN = Productname })
.ToList();
return View(ny);
}
View
#model IEnumerable< MvcApplication2.Models.Product>
#{
ViewBag.Title = "Selectmany";
}
<h2>#ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit http://asp.net/mvc.
</p>
#{
foreach(var k in Model)
{
#K.CategoryName<br/>
#k.Productname<br/>
}
}
Console
var ny = Product.GetAllTeamMembers().SelectMany(x => x.Productname,
(category, withProductlist) =>
new { cat = category.CategoryName, PN = Productname };
foreach(var n in ny)
{
Console.WriteLine(n.cat + "\t" + "-" + n.PN);
}
Output
Choclate -DairyMilkshots DairyMilk Silk DairyMilkFruitsNuts
Vegetables - Tomoto,Pototo,Onion
etc
The problem is that your view is set to handle an explicit type:
#model IEnumerable< MvcApplication2.Models.Product>
But the LINQ method does not return a type of Product. You're actually returning an anonymous type with this portion of the LINQ statement:
(category, withProductlist) => new { cat = category.CategoryName, PN = Productname })
The new keyword helps identify that. Your console application works b/c the anynomous object has properties for PN and CategoryName but does not explicitly need a certain type.
Does that make sense?
As has been suggested, you should just pass in the values from the call Product.GetAllTeamMembers() to your view. Your view should then assign the values for the type. For example,
Controller:
public ActionResult Home()
{
var ny = Product.GetAllTeamMembers();
return view(ny);
}
View
#model IEnumerable< MvcApplication2.Models.Product>
#{
foreach(var k in Model)
{
#K.CategoryName<br/>
#k.Productname<br/>
}
}
}
EDIT
The best way to do what you want is to create a view model to contain the flattened information. This gives you the shape of the data as you want and allows you to use the model in your controller.
New View Model
public class ProductViewModel
{
public string CategoryName { get; set; }
public string ProductName { get; set; }
}
Controller Logic
var ny = Product.GetAllProductName()
.SelectMany(x => x.Productname, (category, withProductlist) =>
new ProductViewModel
{
CategoryName = category.CategoryName,
ProductName = withProductlist
});
The View
#model IEnumerable<ProductViewModel>
The important part is in the select many clause, you're casting to a known type (ProductViewModel) instead of an anonymous type.
Just a fetch a list of Product and take it to view then use the joined table like Product.Cateogry and loop in inner table.

Displaying multiple tables from model in single view

I have two tables TxtComment and Login.
I am displaying image urls from Login table and comments from TxtComment table where username in TxtComment equals username in Login.
I am using Db First approach using entityframework.
How can I concatenate these columns from different tables to one common view? I used ViewBag. I got a result.
Controller
public ActionResult Item(int id)
{
FoodContext db = new FoodContext();
ViewBag.FoodItems = db.FoodItems.Where(row => row.itemid == id);
ViewBag.TxtComments = (from user in db.TxtComments
from ff in db.Logins
where ff.username == user.username
select new { imgurl = ff.imgurl, txtcmt = user.txtcmt });
return View();
}
View
#for(var item in ViewBag.TxtComments)
{
<div>#item</div>
}
The result is {imgurl=http:/sdfsdf,txtcmt=sfsdfsdf}
I need each item seperate. How can I? I tried with #item.imgurl, it says error. Is view bag is better? If not, please help me this need with strongly type view.
Create your own ViewModel instead of putting the model inside the ViewBag.
ViewModel:
public class ViewModel
{
public List<ImageComment> ImageComments { get; set; }
public ViewModel()
{
ImageComments = new List<ImageComment>();
}
}
public class ImageComment
{
public string ImageUrl { get; set; }
public string Comment { get; set; }
}
Controller Action:
public ViewResult Item(int id)
{
FoodContext db = new FoodContext();
List<ImageComment> comments = (from user in db.TxtComments
from ff in db.Logins
where ff.username == user.username
select new ImageComment
{
ImageUrl = ff.imgurl,
Comment = user.txtcmt
}).ToList();
ViewModel vm = new ViewModel{ ImageComments = comments };
return View("MyView", vm);
}
View:
#model ViewModel
#{
ViewBag.Title = "Comments";
}
#foreach(ImageComment comment in Model.ImageComments)
{
<p>#comment.Comment</p>
<img src="#comment.ImageUrl" alt="img" />
}

How to set two values in View()

How can set several objects in view?
public ActionResult Index()
{
var shops = this.context.shops.Select(q => new { q.id, q.name }).ToList();
var bikes = this.context.bikes.Select(q => new { q.id, q.name }).ToList();
return View(shops, bikes); // How to set two values in View()?
}
And parse in View()
#foreach (var r in Model.bikes)
{
<b>#r.name</b>
}
One way is to create a strong typed view model that contains both shops and bikes. Other option could be creating a Tuple and passing as a model to view. I would go first option.
Tuple
var tuple = new Tuple<shop, bike>(new shop(),new bike());
In you view
#Model Tuple<shop,bike>
You need create ViewModel
public class shopsAndbikes
{
public List<shop> shops {get;set;}
public List<bike> bikes {get;set;}
}
public ActionResult Index()
{
shopsAndbikes vm = new shopsAndbikes ()
{
var shops = this.context.shops.Select(q => new { q.id, q.name }).ToList();
var bikes = this.context.bikes.Select(q => new { q.id, q.name }).ToList();
}
return View(vm);
}
View:
#model shopsAndbikes
#foreach (var r in Model.bikes)
{
<b>#r.name</b>
}
#foreach (var r in Model.shops)
{
<b>#r.name</b>
}
Your Model-class should contain properties for both shops and bikes. That is if you use a strongly typed view, it looks that way. Otherwise you could add things to the ViewBag for use in the view.

Categories