Using selected dropdownlist value in query - asp.net-mvc

I am trying to insert data into a sql server temporary table based on a value picked from a dropdownlist. In my model I have 4 classes:
public class Customer
{
[Key]
public int CustID { get; set; }
public string CustName { get; set; }
public virtual ICollection<Sale> Sales { get; set; }
}
}
public class Product
{
[Key]
public int ProductID { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public virtual ICollection<Sale> Sales { get; set; }
}
}
public class Sale
{
[Key]
public int RecordID { get; set; }
public int ProductID { get; set; }
public int CustID { get; set; }
public int InvoiceNo { get; set; }
public int Quantity { get; set; }
public virtual Customer Customer { get; set; }
public virtual Product Product { get; set; }
}
public class TempTable
{
[Key]
public int recordID { get; set; }
public string CustName { get; set; }
public string PoductName { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
public int InvoiceNo { get; set; }
}
In my SaleController I have the following action:
public ActionResult OldInvoice(Sale sale)
{
ViewBag.InvoiceNo = new SelectList(db.Sales, "RecordID", "InvoiceNo", sale.RecordID);
return View();
}
[HttpPost]
public ActionResult OldInvoice(TempTable t, int InvoiceNoToSearch = 0)
{
var query = (from s in db.Sales
join c in db.Customers on s.CustID equals c.CustID
join p in db.Products on s.ProductID equals p.ProductID
where s.InvoiceNo.Equals(s.InvoiceNo == InvoiceNoToSearch)
select new
{
s.InvoiceNo,
s.Quantity,
c.CustName,
p.ProductName,
p.Price
}).ToList();
foreach (var temp in query)
{
t.CustName = temp.CustName;
t.InvoiceNo = temp.InvoiceNo;
t.PoductName = temp.ProductName;
t.Price = temp.Price;
t.Quantity = temp.Quantity;
db.TempTables.Add(t);
db.SaveChanges();
}
return RedirectToAction("OldInvoice");
}
and finally my view is:
#model IEnumerable<UsingDropDownListValueInQuery.Models.Sale>
#{
ViewBag.Title = "OldInvoice";
}
<h2>OldInvoice</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.DropDownList("InvoiceNo")
<p>
<input type="submit" value="Save" />
</p>
}
I get the following error:
Unable to cast the type 'System.Boolean' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.
If I enter in the Where Statement an Existing InvoiceNo it does the job but not if I try to pick the value from the dropdownlist

The problem seems to be that you're never actually sending the value back. In your view, you've created a select named "InvoiceNo", but in your post action, you don't have any parameters that can accept that value. The closest and probably the one you intend to bind to is InvoiceNoToSearch, but if that's the variable you want to use, your view needs to match:
#Html.DropDownList("InvoiceNoToSearch")
Of course, that means your SelectList in ViewBag no longer binds automatically as the options for that select, but that can be fixed by just explicitly specifying it:
#Html.DropDownList("InvoiceNoToSearch", (SelectList)ViewBag.InvoiceNo)

Related

ASP.Net MVC and using Linq to Entities

I'm following an MVC 5 tutorial: http://www.c-sharpcorner.com/article/dashboard-application-with-asp-net-mvc-5-and-jquery/
but the Author left out 1 of the features - the middle panel - "Orders" (which is the orders for all customers). It has a View Details link but no code and partial view is displayed when clicked.
So I'm trying to do create that partial view but having trouble with writing the Linq To Entities.
I am trying for just a partial view that is like a header/multi detail:
CustomerName CustomerImage
OrderDate
Quantity ProductType, ProductName, ProductImage
OrderDate
Quantity ProductType, ProductName, ProductImage
CustomerName CustomerImage
OrderDate
Quantity ProductType, ProductName, ProductImage
Here is the ViewModels I created to represent the above:
public class OrderDetailsViewModel
{
public int Quantity { get; set; }
public string ProductType { get; set; }
public string ProductName { get; set; }
public string ProductImage { get; set; }
}
public class CustomerOrdersViewModel
{
public string CustomerName { get; set; }
public string CustomerImage { get; set; }
public DateTime OrderDate { get; set; }
public ICollection<OrderDetailsViewModel> OrderDetailsViewModel{ get;
set; }
}
Here is the DbContext and the models that the Author created:
DbContext:
public class DashboardContext : DbContext
{
// Constructor - inherits the base constructor.
public DashboardContext() : base("DashboardOrder")
{
}
public IDbSet<Customer> CustomerSet { get; set; }
public IDbSet<Order> OrderSet { get; set; }
public IDbSet<Product> ProductSet { get; set; }
public IDbSet<OrderDetails> OrderDetailSet { get; set; }
}
Customer:
public class Customer : IEntity
{
public Customer()
{
Orders = new List<Order>();
}
public int ID { get; set; }
public string CustomerName { get; set; }
public string CustomerEmail { get; set; }
public string CustomerPhone { get; set; }
public string CustomerCountry { get; set; }
public string CustomerImage { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
IEntity:
public interface IEntity
{
int ID { get; set; }
}
Order:
public class Order : IEntity
{
public Order()
{
OrderDetail = new List<OrderDetails>();
}
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<OrderDetails> OrderDetail { get; set; }
}
OrderDetails:
public class OrderDetails : IEntity
{
public int ID { get; set; }
public int Quatity { get; set; }
public virtual Order Order { get; set; }
public virtual Product Product { get; set; }
}
Product:
public class Product : IEntity
{
public Product()
{
OrderDetails = new List<OrderDetails>();
}
// Auto-implemented properties.
public int ID { get; set; }
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public int UnitsInStock { get; set; }
public string ProductImage { get; set; }
public string ProductType { get; set; }
public virtual ICollection<OrderDetails> OrderDetails { get; set; }
}
Here is the Action Method in the DashboardController I was attempting to write.
I believe I want to read the Order Model which in turn has reference to the Customer and a list of Orders which in turn has a reference to the list of OrderDetail which has reference to the Product.
But I'm having a hard time with the "Linq to SQL" to get the data in the lists in the models to create my ViewModel to flatten it out and pass to my partial view as a list.
public ActionResult GetCustomerOrdersDetails()
{
List<CustomerOrdersViewModel> customerOrders = null;
using (DashboardContext _context = new DashboardContext())
{
// Using LINQ TO SQL and deferred execution via the "ToList".
customerOrders = (from o in _context.OrderSet
select new CustomerOrdersViewModel
{
CustomerName = o.Customer.CustomerName,
CustomerImage = o.Customer.CustomerImage,
OrderDate = o.OrderDate,
-- Here I need to process the list of Orders which in turn has a reference to the list of OrderDetail which has
reference to the Product.
ProductType = ?,
ProductName = ?,
ProductImage = ?,
Quantity = ?,
}).ToList();
}
return PartialView("~/Views/Dashboard/GetCustomerOrdersDetails.cshtml", customerOrders);
}
You first need a .GroupBy() clause to group the records by CustomerName, CustomerImage and OrderDate. Then because OrderDetail is a collection proeprty, you need a .SelectMany() to 'flatten that collection before projecting the result to your OrderDetailsViewModel model.
List<CustomerOrdersViewModel> model = db.OrderSet
.GroupBy(x => new { Name = x.Customer.CustomerName, Image = x.Customer.CustomerImage, Date = x.Date })
.Select(x => new CustomerOrdersViewModel
{
CustomerName = x.Key.Name,
CustomerImage = x.Key.Image,
OrderDate = x.Key.Date,
OrderDetailsViewModel = x.SelectMany(y => y.OrderDetail).Select(y => new OrderDetailsViewModel
{
ProductName = y.Product.ProductName,
Quantity = y.Quantity,
ProductType = y.Product.ProductType,
ProductImage = y.Product.ProductImage
}).ToList()
}).ToList();
return PartialView(model);
Then in the view you can use nested loops to display the details of each order
#model IEnumerable<CustomerOrdersViewModel>
....
#foreach(var order in Model)
{
.... // display details of customer name, date etc
#order.CustomerName
foreach(var item in order.OrderDetailsViewModel)
{
.... // display details of product, quantity etc for each order
#item.ProductName

There is no ViewData item of type 'IEnumerable<SelectListItem> MVC

I've done this EF MVC Application (Code First) with listing/editing/deleting functions. Everything works fine, but now I need to add two dropdown fields. Product has a category and a subcategory which needed to be edited. This is what I have so far:
Main class where ProductSubcategoryID is a foreign key
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string ProductNumber { get; set; }
public int? ProductSubcategoryID { get; set; }
public IEnumerable<SelectList> SelectedCat = new List<SelectList> {};
public IEnumerable<SelectList> SelectedSubCat = new List<SelectList> {};
}
public class ProductCategory
{
public int ProductCategoryID { get; set; }
public string Name { get; set; }
}
public class ProductSubcategory
{
public int ProductSubcategoryID { get; set; }
public int ProductCategoryID { get; set; }
public string Name { get; set; }
}
On the Product controller class I have:
public ActionResult Create()
{
ViewBag.SubcatSelection = new SelectList(dbSubcat.ProductSubcategories, "ProductSubcategoryID", "Name"); ;
return View();
}
and on Edit:
#Html.LabelFor(model => model.ProductSubcategoryID)
#Html.DropDownListFor(model => model.SelectedSubCat, ViewBag.SubcatSelection as SelectList, "ProductSubcategoryID", "Name");
The result:
There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'SelectedSubCat'.

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>

Access ViewModel fields in Edit view

My Model:
public ECmain()
{
this.Notes = new Collection<Notes>();
}
public int ID { get; set; }
public string Auth { get; set; }
public string KeyWords { get; set; }
public string Description { get; set; }
public string URL { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
public string Title { get; set; }
public string Live { get; set; }
public virtual ICollection<Notes> Notes { get; set; }
public virtual ICollection<Email> Email { get; set; }
}
public class MyViewModel
{
public IQueryable<Notes> NotesList { get; set; }
public IQueryable<ECmain> ECmainList { get; set; }
public int ECmain.ID { get; set; }
public IQueryable<Email> EmailList { get; set; }
}
My Controller:
// GET: ECmain/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var viewModel = new MyViewModel
{
ECmainList = from m in db.ECmain.Take(10)
where m.ID == id
select m,
NotesList = from n in db.Notes
where n.ECmainID ==id
select n,
EmailList = from e in db.Email
where e.ECmainID ==id
select e
};
// viewModel.NotesList = new
if (viewModel == null)
{
return HttpNotFound();
}
return View(viewModel);
}
My Edit View:
#model EditSuite.Models.MyViewModel
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.ID )
I want to access the ECmainList.ID The error is
Compiler Error Message: CS1061: 'EditSuite.Models.MyViewModel' does not contain a definition for 'ID'
I tried
#Html.HiddenFor(model => model.ECmainListID.ID )
and
#Html.HiddenFor(Model.model.ECmainListID.ID )
Neither one worked.
It seems pretty obvious from the compiler message:
Compiler Error Message: CS1061: 'EditSuite.Models.MyViewModel' does not contain a definition for 'ID'
So where on the following model is the ID?:
public class MyViewModel
{
public IQueryable<Notes> NotesList { get; set; }
public IQueryable<ECmain> ECmainList { get; set; }
public IQueryable<Email> EmailList { get; set; }
// there is no: public int ID { get; set; } ?
}
I want to access the ECmainList.ID
However, per your model the ECmainList is a IQueryable<ECmain> and the IQueryable<T> also does not have a public property or field called ID. How can you add an editor for a ID of a list of objects? You'd need to loop through the list and have multiple ID fields.

Resources