LINQ Query Parent-Child tables - asp.net-mvc

The problem I'm having goes like this:
I have a textbox in my view that allows search/filter functionality of the Orders table. However, I would like it to be able to also search by the child table OrderDetails and filter appropriately.
The search textbox works for the order table but not the order details.
I realize this code can be shrunk down a lot but I'm new coding.
Something that may help - I'm doing Database first
Here is my code so far.
Controller:
EntitiesDB db = new EntitiesDB();
#region INDEX MAIN PAGE
[HttpGet]
public ActionResult Index(string sortOrder, string currentFilter, int? page, string jobNumberDropDown, string requesitionerDropDown, string supplierDropDown, string dateRequestedDropDown, string dateRequiredDropDown, string searchString)
{
var getSupplierList = db.Suppliers.OrderBy(SL => SL.SupplierName).ToList();
var getEmployeeList = db.Employees.OrderBy(EL => EL.FullName).ToList();
SelectList listOfSuppliers = new SelectList(getSupplierList, "SupplierName", "SupplierName");
SelectList listOfEmployees = new SelectList(getEmployeeList, "FullName", "FullName");
ViewBag.supplierNames = listOfSuppliers;
ViewBag.employeeNames = listOfEmployees;
#region PAGINATION FUNCTION
//Code for Paging
ViewBag.CurrentSort = sortOrder;
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = currentFilter;
int pageSize = 10;
int pageNumber = (page ?? 1);
#endregion
#region SEARCH FUNCTION
//Creates the LINQ Query to select the Orders from the ORDERS table
//var orders = from o in db.Orders join c in db.OrderDetails on o.OrderID equals c.OrderID select new { orders = o.JobNumber, o.PurchaseOrder, c.Description, c.PartNumber, c.AngstromPartNumber };
var orders = from o in db.Orders.Where(x => x.IsDeleted != true) select o; /*-****WORKING FOR ORDER TABLE*****/
var orderDetails = from od in db.OrderDetails.Where(x => x.IsDeleted != true) select od;
//List of Employees
var requesitionerList = new List<string>();
//List of Suppliers
var supplierList = new List<string>();
//List of Job Numbers
var jobNumberList = new List<string>();
//List of Dates Requested
var dateRequestedList = new List<DateTime>();
//List of Dates Required
var dateRequiredList = new List<DateTime>();
//Query the ORDERS table columns
var requesitionerQry = from r in db.Orders.Where(x => x.IsDeleted != true) orderby r.Requesitioner select r.Requesitioner;
var supplierQry = from s in db.Orders.Where(x => x.IsDeleted != true) orderby s.Supplier select s.Supplier;
var jobNumberQry = from j in db.Orders.Where(x => x.IsDeleted != true) orderby j.JobNumber select j.JobNumber;
var dateRequestedQry = from DRqst in db.Orders.Where(x => x.IsDeleted != true) orderby DRqst.DateRequested select DRqst.DateRequested;
var dateRequiredQry = from DRqrd in db.Orders.Where(x => x.IsDeleted != true) orderby DRqrd.DateRequired select DRqrd.DateRequired;
//Searches through the columns filters out NULLS
var t = requesitionerQry.Distinct().ToList().Where(x => String.IsNullOrWhiteSpace(x) == false);
var u = supplierQry.Distinct().ToList().Where(y => String.IsNullOrWhiteSpace(y) == false);
var v = jobNumberQry.Distinct().ToList().Where(z => String.IsNullOrWhiteSpace(z) == false);
var dRT = dateRequestedQry.Distinct().ToList().Where(z1 => String.IsNullOrWhiteSpace(z1.ToString()) == false);
var dRD = dateRequiredQry.Distinct().ToList().Where(z2 => String.IsNullOrWhiteSpace(z2.ToString()) == false);
//Searches through the columns and only pulls out one of each unique string
requesitionerList.AddRange(t);
supplierList.AddRange(u);
jobNumberList.AddRange(v);
dateRequestedList.AddRange(dRT);
dateRequiredList.AddRange(dRD);
//I believe this Grabs the list items and arranges them into a viewable anonamous object
ViewBag.requesitionerDropDown = new SelectList(requesitionerList);
ViewBag.supplierDropDown = new SelectList(supplierList);
ViewBag.jobNumberDropDown = new SelectList(jobNumberList);
ViewBag.dateRequestedDropDown = new SelectList(dateRequestedList);
ViewBag.dateRequiredDropDown = new SelectList(dateRequiredList);
//This defines which columns the text in the search textbox should locate
if (!String.IsNullOrEmpty(searchString))
{
orders = orders.Where(a => a.JobNumber.Contains(searchString)||
//a.Description.Contains(searchString) || a.PartNumber.Contains(searchString) || a.AngstromPartNumber.Contains(searchString) ||
a.Supplier.Contains(searchString) || a.Reason.Contains(searchString) || a.Requesitioner.Contains(searchString) ||
a.DateRequested.ToString().Contains(searchString) || a.DateRequired.ToString().Contains(searchString) ||
a.ExpectedDate.ToString().Contains(searchString) || a.DateOrderPlaced.ToString().Contains(searchString) ||
a.PurchaseOrder.ToString().Contains(searchString));
}
if (!String.IsNullOrEmpty(searchString))
{
orders = orders.Where(x => x.OrderDetails.Any(i => i.Description.Contains(searchString)));
}
//Search the REQUESITIONER column
if (!String.IsNullOrEmpty(requesitionerDropDown))
{
orders = orders.Where(b => b.Requesitioner == requesitionerDropDown);
}
//Search the SUPPLIER column
if (!String.IsNullOrEmpty(supplierDropDown))
{
orders = orders.Where(c => c.Supplier == supplierDropDown);
}
//Search the JOBNUMBER column
if (!String.IsNullOrEmpty(jobNumberDropDown))
{
orders = orders.Where(d => d.JobNumber == jobNumberDropDown);
}
if (!String.IsNullOrEmpty(dateRequestedDropDown))
{
orders = orders.Where(d => d.DateRequested.ToShortDateString() == dateRequestedDropDown);
}
if (!String.IsNullOrEmpty(dateRequiredDropDown))
{
orders = orders.Where(d => d.DateRequired.ToShortDateString() == dateRequiredDropDown);
}
#endregion
//List<Order> OrderList = db.Orders.ToList();
var sortedOrders = orders.OrderBy(x => x.JobNumber);
return View(sortedOrders.ToPagedList(pageNumber, pageSize));
}
#endregion
Here are my Models:
public partial class Order
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Order()
{
this.OrderDetails = new HashSet<OrderDetail>();
}
public System.Guid OrderID { get; set; }
public Nullable<bool> IsDeleted { get; set; }
public string JobNumber { get; set; }
public string Supplier { get; set; }
public string Reason { get; set; }
public string Requesitioner { get; set; }
public System.DateTime DateRequested { get; set; }
public System.DateTime DateRequired { get; set; }
public Nullable<bool> Urgent { get; set; }
public System.DateTime ExpectedDate { get; set; }
public System.DateTime DateOrderPlaced { get; set; }
public string PurchaseOrder { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<OrderDetail> OrderDetails { get; set; }
}
public partial class OrderDetail
{
public System.Guid OrderDetailID { get; set; }
public Nullable<bool> IsDeleted { get; set; }
public int Quantity { get; set; }
public string Description { get; set; }
public string PartNumber { get; set; }
public string Notes { get; set; }
public string Comments { get; set; }
public Nullable<decimal> UnitPrice { get; set; }
public string AngstromPartNumber { get; set; }
public string Manufacturer { get; set; }
public Nullable<int> BoneYard { get; set; }
public System.Guid OrderID { get; set; }
public Nullable<System.Guid> EmployeeID { get; set; }
public Nullable<System.Guid> SupplierID { get; set; }
public virtual Employee Employee { get; set; }
public virtual Order Order { get; set; }
public virtual Supplier Supplier { get; set; }
}

Related

MVC Core How to correctly Edit Existing model using viewmodel

I am trying to Edit existing instance of class project using a viewmodel. I think I have no issues in the GET method of the Edit (everything renders fine on the View) but I am struggling with the POST method. The problem is the POST method creates new instance of the project instead updating the current one.
This is my model:
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
public string Budget { get; set; }
public string BusinessCase { get; set; }
public string StartDate { get; set; }
public string FinishDate { get; set; }
public int ClientId { get; set; }
public Client Client { get; set; }
public ICollection<ProjectMember> ProjectMembers { get; set; }
public Project()
{
}
}
}
This is my CreateProjectViewModel (some of the attributes are not used in the controller code below):
public class CreateProjectViewModel
{
//project
public int ProjectId { get; set; }
public string Name { get; set; }
public string Budget { get; set; }
public string BusinessCase { get; set; }
public string StartDate { get; set; }
public string FinishDate { get; set; }
//clients
public int ClientId { get; set; }
public Client Client { get; set; }
public ICollection<ProjectMember> ProjectMembers { get; set; }
//Members
public int MemberId { get; set; }
public Member Member { get; set; }
public Project Project { get; set; }
public List<SelectListItem> Members { get; set; }
public IEnumerable<SelectListItem> Clients { get; set; }
public IEnumerable<int> SelectedMembers { get; set; }
public CreateProjectViewModel() { }
}
}
This is My Edit GET method in ProjectController:
public async Task<IActionResult> Edit(int? id)
{
Project project = await _context.Project
.FirstOrDefaultAsync(m => m.ProjectId == id);
var members = _context.Member
.Select(m => new SelectListItem { Value = m.MemberId.ToString(), Text = m.MemberName }).ToList();
var clients = _context.Client
.Select(r => new SelectListItem { Value = r.ClientId.ToString(), Text = r.Name }).ToList();
CreateProjectViewModel viewmodel = new CreateProjectViewModel
{
Name = project.Name,
Budget = project.Budget,
BusinessCase = project.BusinessCase,
StartDate = project.StartDate,
FinishDate = project.FinishDate,
Project = project,
Clients = clients,
Members = members
};
return View(viewmodel);
This is my Edit POST method in ProjectController which is wrongly creating a new project instead of updating the current project:
(The controller is trying to save values to Project Model and at the same time in Join table containing MemberId and ProjectID - this works fine when creating a project, not sure if correct for updating)
public IActionResult Edit(int? id, CreateProjectViewModel model)
{
Project project = _context.Project
.Single(m => m.ProjectId == id);
//this is to post in many-to-many join table between Member and Project
var projectID = project.ProjectId;
var memberID = model.MemberId;
IList<ProjectMember> existingItems = _context.ProjectMembers
.Where(cm => cm.MemberId == memberID)
.Where(cm => cm.ProjectId == projectID).ToList();
if (existingItems.Count == 0)
{
foreach (var selectedId in model.SelectedMembers)
{
_context.ProjectMembers.Add(new ProjectMember
{
ProjectId = project.ProjectId,
MemberId = selectedId,
});
}
}
//this is to update the values in the project which refers to ProjectID
project.ProjectId = model.ProjectId;
project.Name = model.Name;
project.Budget = model.Budget;
project.BusinessCase = model.BusinessCase;
project.StartDate = model.StartDate;
project.FinishDate = model.FinishDate;
project.ClientId = model.ClientId;
_context.Entry(project).State = EntityState.Modified;
_context.SaveChanges();
return RedirectToAction("Index");
}
Can you guys advise me what should be changed in either method to get the expected result?
Thanks a lot.
After some digging done this is the working code.
Edit POST Method:
public IActionResult Edit(int? id, CreateProjectViewModel viewmodel)
{
if (ModelState.IsValid)
{
var project = _context.Project
.SingleOrDefault(m => m.ProjectId == id);
//this is to update the Project from the viewmodel
project.Name = viewmodel.Name;
project.Budget = viewmodel.Budget;
project.BusinessCase = viewmodel.BusinessCase;
project.StartDate = viewmodel.StartDate;
project.FinishDate = viewmodel.FinishDate;
project.ClientId = viewmodel.ClientId;
//code below is to validate if the matched primary keys of Project and Member are not already in ProjectMembers table
foreach (var selectedId in viewmodel.SelectedMembers)
{
var projectID = project.ProjectId;
var memberID = selectedId;
IList<ProjectMember> existingItems = _context.ProjectMembers
.Where(cm => cm.MemberId == memberID)
.Where(cm => cm.ProjectId == projectID).ToList();
if (existingItems.Count == 0)
{
//this is to add new entry into ProjectMembers table
_context.ProjectMembers.Add(new ProjectMember
{
ProjectId = project.ProjectId,
MemberId = selectedId,
});
}
}
_context.SaveChanges();
}
return RedirectToAction("Index");

Return data from multiple tables using LINQ Method Syntax

I have got problem with return data from my database. In my database are three tables: Customer, Activity and CustomerActivity. I want to return activities data for specific customer and with specific type activity. I wrote query but it doesn't work exactly as I wish. Here is my code and tables. Thank you for advices.
var activities = db.Join(db.CustomerActivities, a => a.ActivityID, ca =>ca.CustomerActivityID, (a, ca) => new { Activity = a, CustomerActivity = ca })
.Where(a => a.CustomerActivity.customer.CustomerID == id && a.Activity.TypeActivityID == typeActivity)
.Select(m => new ActivityMV()
{
ActivityID = m.Activity.ActivityID,
Name = m.Activity.Name,
DateOfActivity = m.Activity.DateOfActivity,
Desc = m.Activity.Desc
})
.ToList();
public class CustomerActivity
{
public int CustomerActivityID { get; set; }
public int CustomerID { get; set; }
public int ActivityID { get; set; }
public virtual Customer customer { get; set; }
public virtual Activity activity { get; set; }
}
public class Activity
{
public int ActivityID { get; set; }
public string Name { get; set; }
public string Desc { get; set; }
public string DateOfActivity { get; set; }
public string TypeActivityID { get; set; }
public virtual ICollection <CustomerActivity> customerActivities { get; set; }
}
Try
var activities = db.CustomerActivities
.Where(ca => ca.CustomerID == id && ca.Activity.TypeActivityID == typeActivity)
.Select(ca => new ActivityMV()
{
ActivityID = ca.ActivityID,
Name = ca.Activity.Name,
DateOfActivity = ca.Activity.DateOfActivity,
Desc = ca.Activity.Desc
})
.ToList();

'No property or field 'GoodName' exists in type 'GoodDomain'' for server side processing in jquery datatable?

I'm using jquery datatable for showing my data.I want to use server side proccesing in jquery datatable using asp.net mvc but I've a problem with it.I have a class that it hasn't GoodName property but I want to sort my table based on GoodName property.but i've got error 'No property or field 'GoodName' exists in type 'GoodDomain' I know that GoodName doesn't exist in GoodDomian but i can access GoodName property by navigation property Good.GooName but I can't use it in this statement.because I've used Linq.Dynamic
query = query.OrderBy(orderByString == string.Empty ? "GoodName asc + " : orderByString);
public ActionResult LoadData([ModelBinder(typeof(DataTablesBinder))] IDataTablesRequest requestModel)
{
IQueryable<GoodDomain> query = db.GoodDomains;
var totalCount = query.Count();
#region Filtering
// Apply filters for searching
if (requestModel.Search.Value != string.Empty)
{
var value = requestModel.Search.Value.Trim();
query = query.Where(p =>
p.Good.GoodName.Contains(value)
);
}
var filteredCount = query.Count();
#endregion Filtering
#region Sorting
// Sorting
var sortedColumns = requestModel.Columns.GetSortedColumns();
var orderByString = String.Empty;
foreach (var column in sortedColumns)
{
orderByString += orderByString != String.Empty ? "," : "";
orderByString += (column.Data) + (column.SortDirection == Column.OrderDirection.Ascendant ? " asc" : " desc");
}
query = query.OrderBy(orderByString == string.Empty ? "MinRage asc + " : orderByString); // I've a problem
//query =db.GoodDomains.OrderBy( g => g.Good.GoodName)
#endregion Sorting
// Paging
query = query.Skip(requestModel.Start).Take(requestModel.Length);
var data = query.Select(g => new
{
GoodDomainID = g.GoodDomainID,
GoodName = g.Good.GoodName,
GoodHeadName = g.GoodHead.GoodHeadName,
GoodFootName = g.GoodFoot.GoodFootName,
WorkhouseName = g.Workhouse.WorkhouseName,
MinRange = g.MinRange,
MaxRange = g.MaxRange,
}).ToList();
return Json(new DataTablesResponse(requestModel.Draw, data, filteredCount, totalCount), JsonRequestBehavior.AllowGet);
}
public class GoodDomain
{
[Key]
public int GoodDomainID { get; set; }
public Nullable<int> GoodHeadeId { get; set; }
public virtual GoodHead GoodHead { get; set; }
public Nullable<int> GoodFootId { get; set; }
public virtual GoodFoot GoodFoot { get; set; }
public Nullable<int> GoodId { get; set; }
public virtual Good Good { get; set; }
[Display(Name = "نام کارگاه")]
public Nullable<int> WorkhouseId { get; set; }
public virtual Workhouse Workhouse { get; set; }
public Nullable<int> MaxRange { get; set; }
public Nullable<int> MinRange { get; set; }
}

How to join two tables in linq and not get anonymous type result set

I would like to get a result set from both PriceAssocationLookup and PriceAssociation tables. How do I do this and not get an error due to Anonymous Type?
Here is my code:
IEnumerable<IPriceAssociationLookupRepository> IPriceAssociationLookupRepository.GetPacs(string upc)
{
using (PortalDataEntities entities = new PortalDataEntities())
{
var priceAssociationLookups = (from priceassociationlookup in entities.PriceAssociationLookups
join priceassociation in entities.PriceAssociations on priceassociationlookup.PriceAssociationCode equals priceassociation.PriceAssociationCode
where priceassociationlookup.Upc == upc
select priceassociationlookup ).ToList();
return priceAssociationLookups;
}
}
Create a ViewModel and add properties for the columns you want to return and return List of the view model type, here is my code, the way i used to do :
List<PreviousTest> Result = (from d in db.dc_tpatient_bookingd
join og in db.dc_tp_organization
on d.clientid equals og.OrgId into a
from og in a.DefaultIfEmpty()
from t in db.dc_tp_test
from p in db.dc_tp_tprocess
where d.bookingid == BookingID
&& t.TestId == d.testid
&& d.ProcessID == p.processid
&& d.bookingdid != BookingDID
select new PreviousTest
{
BookingID = d.bookingid,
BookingDId = d.bookingdid,
TestID = t.TestId,
TestName = t.Test_Name,
ProcessName = p.name,
ProcessID = p.processid,
ClientID = d.clientid
}).ToList();
Here is my viewmodel :
public class PreviousTest
{
public long BookingID { get; set; }
public long BookingDId { get; set; }
public long TestID { get; set; }
public string TestName { get; set; }
public long ProcessID { get; set; }
public string ProcessName { get; set; }
public string ClientID { get; set; }
}

Exception NullReferenceException in controller (asp.net mvc)

There are Supplier model and User model in my project, every Supplier has a few Users
Supplier model
public class SupplierRow
{
public Guid Id { get; set; }
public string FullName { get; set; }
public bool Subscribed { get; set; }
public bool Active { get; set; }
public int Visits { get; set; }
public List<UserRow> Users { get; set; }
public bool AllInactive
{
get
{
foreach (UserRow ur in Users)
{
if (ur.Status == 1) return false;
}
return true;
}
}
}
and User model
public class UserRow
{
public Guid Id { get; set; }
public string FullName { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Status { get; set; }
public int Role { get; set; }
public Guid SupplierId { get; set; }
}
then I use my models in controller
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<Guid> supplierIds = new List<Guid>();
foreach (SupplierRow sr in suppliers)
{
supplierIds.Add(sr.Id);
}
var users = Context.Users.AsNoTracking()
.Where(e => supplierIds.Contains(e.SupplierId.Value))
.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.Value
}).ToList();
foreach (UserRow ur in users)
{
foreach (SupplierRow sr in suppliers)
{
if (ur.SupplierId == sr.Id)
{
sr.Users.Add(ur);
}
}
}
return PartialView("_Grid", suppliers);
}
but when I try to debug my project I get some exception here
What's wrong? How can I fix that?
Your Users list are not initialized. Create a new list before accessing it Users = new List<UserRow>(); You can change the SupplierRow class:
public class SupplierRow {
private List<UserRow> users = new List<UserRow>();
public List<UserRow> Users
{
get { return users; }
set { users = value; }
}
...
}
or in the constructor:
public class SupplierRow
{
public SupplierRow()
{
Users = new List<UserRow>();
}
public List<UserRow> Users { get; set; }
...
}
or before accessing it:
foreach (UserRow ur in users)
{
foreach (SupplierRow sr in suppliers)
{
sr.Users = new List<UserRow>();
if (ur.SupplierId == sr.Id)
{
sr.Users.Add(ur);
}
}
}
or you can just use linq:
foreach (SupplierRow sr in suppliers)
{
sr.Users = users.Where(user => user.SupplierId == sr.Id);
}
return PartialView("_Grid", suppliers);

Resources