Mixing local list operations with linq to entities database operations - asp.net-mvc

I have 2 lists. A shopping cart list, which contains a objects with the properties; Quantity and ProductId. I then get all products from the repository (IQueryable) that has ProductId in the shopping cart list. This means that for every product, there is a shopping cart object with the Quantity related to it.
When doing the select, I want to assign this Quantity also, but the only way I know to do this is to query the cart again.
For egx.
model = (from p in productService.GetAllProducts()
where cart.Entries.Select(c => c.ProductId).Contains(p.ProductId)
select new CartViewItem
{
Price = p.Price,
ProductId = p.ProductId,
ProductName = p.ProductName,
Quantity = cart.Entries.FirstOrDefault(c => c.ProductId == p.ProductId).Quantity
}).ToList();
Model:
public class ShoppingCartEntry
{
public int ProductId { get; set; }
public int Quantity { get; set; }
}
cart.Entries is not coming from a repository. productService.GetAllProducts() returns an entityframework's IQueryable.
EDIT: My new code is:
model= (from p in productService.GetAllProducts()
from c in cart.Entries
where c.ProductId == p.ProductId
select new CartViewItem
{
Price = p.Price,
ProductId = p.ProductId,
ProductName = p.ProductName,
Quantity = c.Quantity
}).ToList();
This throws an error:
Unable to create a constant value of type 'SampleApp.WebUI.Models.ShoppingCartEntry'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.

i think this should work...
var model = (from c in cart.Entires // The small local cart collection
let cpid = cart.Entires.Select(c2 => c2.ProjectId) //
from p in productService.GetAllProducts() // Query all Products used in cart
.Where(queryp => cpid.Contains(queryp.ProjectId)).ToList()
where p.ProductId == c.ProductId
select new CartViewItem {
p.Price,
p.ProductId,
p.Brand,
p.ProductName,
Discount = p.DiscountPercent * c.Quantity}).ToList();

Related

LINQ JOIN with WHERE condition

I have a problem with the creation of LINQ query with lambda expression. I need join two tables and make some conditions. I have two tables MSR and BOMDetail.
MSR had theese columns -> MSRID, PN, Buyer,Plant EditDate.
BomDetail had theese columns -> BOMID, PN, AltQty, Plant, EditDate.
And i need to write this query into LINQ.
SELECT MSR.PN, Buyer, MSR.EditDate, MSR.Plant FROM MSR
JOIN BomDetail bd ON MSR.PN = bd.PN AND MSR.Plant = bd.Plant
WHERE LEN(ISNULL(bd.AltQty,''))>0
I need to make 2 conditions PN must equals between tables and Plant's too.
I have for result ViewModel in asp.net MVC.
public class MSRViewModel
{
public string PN { get; set; }
public string Buyer { get; set; }
public string Plant { get; set; }
public DateTime EditDate { get; set; }
}
And here is my sample, it works fine, but i don't know where i must write the second condition for bd.Plant = MSR.Plant.
var data = DbContext.BomDetails.Where(x => !string.IsNullOrEmpty(x.AltQty))
.Join(DbContext.MSRs
, bd => bd.PN,
msr => msr.PN,
(bd, msr) => new MSRViewModel
{
PN = msr.PN,
Buyer = msr.Buyer,
Plant = msr.Plant,
EditDate = msr.EditDate
}).ToList().AsEnumerable();
Thanks.
You can do this as follows:
var data = DbContext.BomDetails.Where(x => !string.IsNullOrEmpty(x.AltQty))
.Join(DbContext.MSRs
, bd => new { bd.PN, bd.Plant },
msr => new { msr.PN, msr.Plant },
(bd, msr) => new MSRViewModel
{
PN = msr.PN,
Buyer = msr.Buyer,
Plant = msr.Plant,
EditDate = msr.EditDate
}).ToList().AsEnumerable();

MVC db.SaveChanges(); 2 Times Error: Object reference not set

I'm getting the error of Object reference not set to an instance of an object. because of the Cart does not exist before it saves the db with the new changes.
I made some notes in my code explaining the problem. And I'm trying to get done
[Authorize]
public ActionResult AddToCart(int productid, string name, string description, decimal price)
{
var userID = User.Identity.GetUserId();
// List of Cart(s) that the current user own.
List<Cart> Carts = db.Carts.Where(x => x.UserId == userID).ToList();
// checks if the list above cotains no cart for the current logged in user.
if (Carts.Find(m => m.UserId == userID) == null) {
Cart cartmodel = new Cart { UserId = userID, CreatedDate = DateTime.Now};
db.Carts.Add(cartmodel);
db.SaveChanges();
}
// this action needs to be delayed til the upper action has been executed because: userCart.Id; has no value yet!
var userCart = Carts.Find(x => x.Id == x.Id);
var MyCartId = userCart.Id;
OrderItem model = new OrderItem { ProductId = productid, Name = name, Description = description, Price = price, CartId = MyCartId, Quantity = 1 };
db.OrderItems.Add(model);
db.SaveChanges();
return RedirectToAction("Cart");
}
Object reference not set
at
var MyCartId = userCart.Id;
The code works if the cart already exists. so after getting the error it does create the Cart for the user but it doesn't do the 2nd action which was to add product to the cart
i attempted to do this but now getting a new error:
[Authorize]
public ActionResult AddToCart(int productid, string name, string description, decimal price)
{
var userID = User.Identity.GetUserId();
// List of Cart(s) that the user owns should allways be 1 only ofc.
List<Cart> Carts = db.Carts.Where(x => x.UserId == userID).ToList();
// checks if the list above cotains no cart for the current logged in user.
if (Carts.Find(m => m.UserId == userID) == null) {
return RedirectToAction("AddNewCart");
}
// this action needs to be delayed til the upper action has been executed becasue: userCart.Id; has no value yet!
// make 2 action results and work with redirect
var userCart = Carts.Find(x => x.Id == x.Id);
var MyCartId = userCart.Id;
OrderItem model = new OrderItem { ProductId = productid, Name = name, Description = description, Price = price, CartId = MyCartId, Quantity = 1 };
db.OrderItems.Add(model);
db.SaveChanges();
return RedirectToAction("Cart");
}
public ActionResult AddNewCart()
{
var userID = User.Identity.GetUserId();
// List of Cart(s) that the user owns should allways be 1 only ofc.
List<Cart> Carts = db.Carts.Where(x => x.UserId == userID).ToList();
Cart cartmodel = new Cart { UserId = userID, CreatedDate = DateTime.Now };
db.Carts.Add(cartmodel);
db.SaveChanges();
return RedirectToAction("AddToCart");
}
the parameters dictionary contains a null entry for parameter 'productid' of non-nullable type 'System.Int32' for method
'System.Web.Mvc.ActionResult AddToCart(Int32, System.String,
System.String, System.Decimal)' in
'BlogMVC.Controllers.WebshopController'. An optional parameter must be
a reference type, a nullable type, or be declared as an optional
parameter.
Parameter name: parameters
I fixed it, but it isnt exacly a clean way of doing it any suggestion to make the code more clean and better would be greatly appciated
[Authorize]
public ActionResult AddToCart(int productid, string name, string description, decimal price)
{
var userID = User.Identity.GetUserId();
// List of Cart(s) that the user owns should allways be 1 only ofc.
List<Cart> Carts = db.Carts.Where(x => x.UserId == userID).ToList();
// checks if the list above cotains no cart for the current logged in user.
if (Carts.Find(m => m.UserId == userID) == null) {
return RedirectToAction("AddNewCart", new { name = name, productid = productid, description = description, price = price });
}
// this action needs to be delayed til the upper action has been executed becasue: userCart.Id; has no value yet!
// make 2 action results and work with redirect
var userCart = Carts.Find(x => x.Id == x.Id);
var MyCartId = userCart.Id;
OrderItem model = new OrderItem { ProductId = productid, Name = name, Description = description, Price = price, CartId = MyCartId, Quantity = 1 };
db.OrderItems.Add(model);
db.SaveChanges();
return RedirectToAction("Cart");
}
public ActionResult AddNewCart(int productid, string name, string description, decimal price)
{
var userID = User.Identity.GetUserId();
// List of Cart(s) that the user owns should allways be 1 only ofc.
List<Cart> Carts = db.Carts.Where(x => x.UserId == userID).ToList();
Cart cartmodel = new Cart { UserId = userID, CreatedDate = DateTime.Now };
db.Carts.Add(cartmodel);
db.SaveChanges();
return RedirectToAction("AddToCart", new { name = name, productid = productid, description = description, price = price });
}

Some errors in controller (asp.net mvc)

I am getting some errors in my controller.
At first, I got Suppliers List, then I got Id for all Suppliers, then I got all Users for every Supplier.
public ActionResult Grid(bool? active)
{
var suppliers = Context.Suppliers.AsNoTracking()
.WhereIf(active != null, e => e.Active == active)
.Select(e => new SupplierRow
{
Id = e.Id,
FullName = e.FullName,
Active = e.Active,
Visits = e.Visits,
})
.ToList();
List<int> supplierIds = new List<int>();
foreach (SupplierRow sr in suppliers)
{
supplierIds.Add(sr.Id);
}
var users = Context.Users.AsNoTracking()
.Where(e => supplierIds.Contains(e.SupplierId))
.Select(e => new UserRow
{
Id = e.Id,
FullName = e.FullName,
Email = e.Email,
Name = e.Name,
Status = e.Status,
Role = e.Role,
SupplierId = e.SupplierId
}).toList();
foreach (UserRow ur in users)
{
foreach (SupplierRow sr in supplier)
{
if (ur.SupplierId == sr.Id)
{
sr.Users.Add(ur);
}
}
}
return PartialView("_Grid", suppliers);
}
here
and here
What's wrong with my code? How to fix that?
The problem is that you are trying to add Guid object to a collection that only accepts int values. Your User.SupplierId is an object of type Guid? (or Nullable<Guid>), while Supplier.Id is Guid. Fix the collection by declaring it as:
List<Guid> supplierIds = new List<Guid>();
Then in you code use:
foreach(SupplierRow sr in suppliers)
{
supplierIds.Add(sr.Id);
}
Do the same thing for users except that you will have to use SupplierId.HasValue and SupplierId.Value to check whether it has a value and to read the value. This is because it is declared as nullable Guid.

selecting multiple columns and looping through the selected rows

I want to be able to select multiple columns and loop through the retrieved rows and store the selected fields in a string.
Something like select a.firstname, a.lastname from customer where a.id = '123' and loop through the retireved rows and have them write to a string like
FirstName = John; LastName = Doe
FirstName = Steve; LastName = Smith
I have linq statement as
IList<string> strgradeandbatch = new List<string>();
strgradeandbatch = context.GradeAndBatches
.Where(T => T.RequestGuid == request.ItemGuid)
.Select(T => new{T.GradeName, T.Batch}).ToList();
Obviously this is wrong, and not sure how to do it.Thanks for your help in advance
I think you are almost correct. Just remove IList<string> strgradeandbatch = new List<string>() and use anonymous type var strgradeandbatch.
string GradeName, Batch;
var strgradeandbatch = context.GradeAndBatches
.Where(T => T.RequestGuid == request.ItemGuid)
.Select(T => new{T.GradeName, T.Batch}).ToList();
foreach(var item in strgradeandbatch)
{
GradeName = item.GradeName;
Batch = item.Batch;
}
(Note:If you use anonymous type, you can't return this value from the method)
The Select method projects the query results into a list of an anonymous type objects, so it can be used with a list for strings.
One solution is to create a new class
public class Grade
{
public string GradeName {get; set;}
public string Batch {get; set;}
}
Which is going to be used with the Select method
var strgradeandbatch = context.GradeAndBatches
.Where(T => T.RequestGuid == request.ItemGuid)
.Select(T => new Grade
{
GradeName = T.GradeName,
Batch = T.Batch
}).ToList();

Seat Reserving system

the Image shows how my tables are setup
Update
I have a working reserve seat and add to booking table now.
//
// POST: /Home/CreateBooking
public ActionResult CreateBooking(String id, DateTime date, DateTime time)
{
ViewData["username"] = User.Identity.Name;
ViewData["performanceDate"] = date;
ViewData["Venue"] = id;
BookingCreate model = new BookingCreate();
model.Seats = (from c in _db.Seat
where c.venue == id
select c);
return this.View(model);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateBooking(BookingCreate bookingCreate, IList<String> seatNumber)
{
Customer theCustomer
= (from c in _db.Customer
select c).First<Customer>(c => c.username == bookingCreate.customer);
//performance details for the performance selected by the user
Performance thePerformance
= (from p in _db.Performance
select p).FirstOrDefault<Performance>(p => p.performanceDate == bookingCreate.performanceDate || p.performanceTime == bookingCreate.performanceTime || p.venue == bookingCreate.venue);
//performance details for the performance selected by the user
Performance seatbooking
= (from p in _db.Performance
select p).FirstOrDefault<Performance>(p => p.performanceDate == bookingCreate.performanceDate || p.performanceTime == bookingCreate.performanceTime || p.venue == bookingCreate.venue);
var now = DateTime.UtcNow;
var bookingToCreate = new Booking();
bookingToCreate.bookingDate = now;
bookingToCreate.bookingTime = now;
bookingToCreate.bookingType = "Web";
bookingToCreate.collect = true;
bookingToCreate.Customer = theCustomer;
bookingToCreate.Performance = thePerformance;
_db.AddToBooking(bookingToCreate);
_db.SaveChanges();
var bookingnumber = (from p in _db.Booking
select p.bookingNo);
foreach (var displaySeat in seatNumber)
{
Seat theseat
= (from c in _db.Seat
select c).FirstOrDefault<Seat>(c => c.seatNumber == displaySeat);
var seatBooking = new SeatBooking();
seatBooking.Booking = bookingToCreate;
seatBooking.Seat = theseat;
_db.AddToSeatBooking(seatBooking);
_db.SaveChanges();
}
return RedirectToAction("ShowsIndex");
}
The code ensures that the correct venue's seats are displayed and that the logged in user and selected performance is chosen.
What i am stuck with is..
I am currently outputting the seats as checkboxes
with
BookingCreate model = new BookingCreate();
model.Seats = (from c in _db.Seat
where c.venue == id
select c);
But I would like for the checkboxes to show what seat number they relate to (at the moment they are just a blank checkbox)
And also how to stop showing seats that have been booked to stop duplication.
Thanks
I would do it this way (providing there are surrogate primary keys Customer.Id and Performance.Id)
public class BookingToCreateVM
{
public int BookingNo{get; set;}
//..etc - all necessary booking fields
public Guid UserId{get; set;}
public Guid PerformanceId{get; set;}
//data for something like dropdowns in view
public IList<Customer> Users{get; set;}
public IList<Performance> Performances{get; set;}
}
and the controller action
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateBooking(BookingToCreateVM bookingToCreateVM)
{
Customer theCustomer
= (from c in _db.Customer
select c).Single<Customer>(c=>c.Id == bookingToCreateVM.UserId);
Performance thePerformance
= (from p in _db.Performance
select p).Single<Performance>(p=> p.Id == bookingToCreateVM.PerformanceId);
var bookingToCreate = new Booking();
bookingToCreate.BookingNo= bookingToCreateVM.BookingNo;
//..etc - initialize all necessary fields
bookingToCreate.Customer = theCustomer;
bookingToCreate.Performance = thePerformance;
_db.AddToBooking(bookingToCreate);
_db.SaveChanges();
return RedirectToAction("ListBookings");
}

Resources