selecting multiple columns and looping through the selected rows - asp.net-mvc

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();

Related

Orderby clause not working with drop down list in mvc

I am populating a drop down list using Linq and the orderby clause doesn't seem to work.
public List<Hello> getManagers()
{
var que = (from man in db.Table1
where man.Role == "Manager"
orderby man.Name
select new Hello
{
Managers = man.Name
}).Distinct().ToList();
return que;
}
Controller Class:
public ActionResult Index()
{
rp = new RequestProcess();
ViewBag.ID = fillSelectedList("", "ID", rp);
ViewBag.Managers = fillSelectedList("", "Managers", rp);
return View(""); //View 1
}
public static List<SelectListItem> fillSelectedList(string selValue, string type, RequestProcess rp )
{
List<SelectListItem> list = new List<SelectListItem>();
SelectListItem obj = new SelectListItem();
if (type == "Managers") {
var tempList= rp.getManagers();
tempList.ForEach(x =>
{
obj = new SelectListItem();
obj.Text = x.Managers;
obj.Value = x.Managers;
obj.Selected = x.Managers == selValue ? true : false;
list.Add(obj);
});
}
return list;
}
I am still receiving an un-ordered list. Any fixes?
The result is not ordered, because method Distinct does not return ordered results. What you need to do instead is to first call Disctinct, and only then OrderBy:
var que = (from man in db.Table1
where man.Role == "Manager"
select new Hello
{
Managers = man.Name
}).Distinct() // <- First distinct ...
.OrderBy(x => x.Managers) // <- ... then order by
.ToList();
As mentioned in the answer above, you need to sort the result after Distinct().
Also note that you are mixing Lambda expression and LINQ to Entities Queries... you may want to consider choosing one of them for consistency (though there is no syntax error if you mix them). This is the same query using lambda expression:
var que = _context.Table1
.Where(m => m.Role == "Manager")
.Select(h => new Hello { Managers = h.Name })
.Distinct()
.OrderBy(o => o.Managers)
.ToList();

how to return selected columns based on user choice

I'm trying to limit which fields are returned by an API based on a parameter called fields which I accept multiple strings doing this
private readonly string[] fields;
public string[] SelectiveSerializer(string fields)
{
string[] _fields;
var fieldColl = fields.Split(',');
_fields = fieldColl
.Select(f => f.ToLower().Trim())
.ToArray();
return _fields;
}
I want to be able to choose what I return based on whatever the user gives me in _fields. Normal way to do it:
var linq = (from entity in db.users
where entity.ID== id
&& entity.ON== false
select( new {
ID = entity.ID,
FirstName = entity.FirstName,
LastName =entity.LastName,
FotherName = entity.FotherName
}).ToList();
but here I have to specify the fields in Select (ID, FirstName ..etc), which I want it to be dynamic based on what fields[] has. Is there a way to do this?
sort of this (which is wrong):
var linq = (from entity in db.users
where entity.ID== id
&& entity.ON== false
select( new {
foreach (string s in _fields)
{
entity.s;
}
}).ToList();
Use a ternary expression for each assignment
var user = entityContext.Users.Where(u => u.ID == id)
.Select(u => new {
ID = _fields.Contains['id'] ? u.ID : 0,
FirstName = _fields.Contains['firstname'] ? u.FirstName : null,
LastName = _fields.Contains['lastname'] ? u.LastName : null,
otherName = _fields.Contains['othername'] ? u.otherName : null
})
.ToList();
I also would put the field names in a HashSet<string> for a better performance.
var _fields = new HashSet<string>(fields.Split(',').Select(f => f.ToLower().Trim()));
This solution keeps all the properties but sets the unwanted ones to null. If you want to dynamically add properties, see this other SO question: How to dynamically create a class in C#?. But note that this only useful in scenarios where objects of this type are processed dynamically as well.
I was finally able to do this with minimal work.
assuming the filter is a string list. string array.
so to avoid reflection and all that jazz, I iterate over each record and see if the variable is in the filter list, then create a dic entry with (var,val) assuming that no duplicate var in the same record, which can be catch if you want but I don't have this issue.
Then at the end add that dic to a list.
the method accept anonymous type list and a filter list.
public static List<Dictionary<string, object>> filteredList(IEnumerable source, string[] filter)
{
var filteredList = new List<Dictionary<string, object>>();
foreach (var single in source)
{
var type = single.GetType();
var props = type.GetProperties();
var singleRecord = new Dictionary<string, object>();
foreach (var v in props)
{
if (filter.Contains(v.Name))
{
var tempValue = type.GetProperty(v.Name).GetValue(single, null);
singleRecord.Add(v.Name, tempValue);
}
}
filteredList.Add(singleRecord);
}
return filteredList;
}

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.

Mixing local list operations with linq to entities database operations

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();

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