While following the learning package at https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/crud, I want to know what changes to be made in the following code so as to have the Course Details table be available in the sortable manner (like on the Index page at https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/sort-filter-page). I can call the Details method with an argument delivering the sort manner required but how to have the var student use the OrderBy & OrderByDescending since the same are complained by the Visual Studio to be not IQueryable in nature:
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var student = await _context.Students
.Include(s => s.Enrollments)
.ThenInclude(e => e.Course)
.AsNoTracking()
.SingleOrDefaultAsync(m => m.ID == id);
if (student == null)
{
return NotFound();
}
return View(student);
}
While code for the Index page, like the following, works great for the var students:
public async Task<IActionResult> Index(string sortOrder)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
var students = from s in _context.Students
select s;
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
return View(await students.AsNoTracking().ToListAsync());
}
Thanks in advance.
Update
I guess, I am not presenting the problem well enough. Let's consider another example:
public async Task<IActionResult> Details(string _AccId)
{
if (_AccId == null)
{
return NotFound();
}
var accs = await _context.Accounts
.Include(Cust => Cust.Customers) //To reflect the Name of the Customer to whom the account belongs
.Include(Bal => Bal.Balances).OrderByDescending(Balances.Report_Date) //For relevant Sub-Table on Accounts' detail page to show the balances on in shape of Report_Date (but in a descending sorted manner)
.SingleOrDefaultAsync(m => m.SrcSys == _SrcSys && m.CustId == _CustId && m.AccId == _AccId);
return View(accs);
}
In other words only the Balances Table reflecting balances in a manner sorted.
Thanks again.
Related
When running this code:
public async Task<IActionResult> AddMessage()
{
int distid = ViewBag.DISTRIBUTORID;
ViewBag.PageName = "Send Message";
int id = Convert.ToByte(ViewBag.ID);
ViewBag.UserId = id;
var messages = await _companyContext.MESAJLAR.Where(p => p.SENDERID == id || p.SENTID == id).OrderBy(p => p.DATE).GroupBy(p => p.SPECIALID).Select(p => p.Last()).ToListAsync();
var ids1 = messages.Select(p => p.SENDERID).ToArray();
var ids2 = messages.Select(p => p.SENTID ).ToArray();
var users= await _userDatabaseContext.user.Where(p => p.DISTID == distid && p.ID != id && !ids1.Contains(p.ID) && !ids2.Contains(p.ID)).ToListAsync();
return View(new AddMessageViewModel
{
USERS= users
});
}
I get the following error:
Queries performing 'Last' operation must have a deterministic sort order.Rewrite the query to apply an 'OrderBy' operation on the sequence before calling 'Last'.
I'm getting it at the line that starts with var messages = ...
The Problem with your query is, that you are trying to select .Last() without ordering your data first.
Right now you are ordering your data, then group it and after that you try to select 'Last()'.
You have to order the grouped data to use '.Last()'.
var messages = await _companyContext.MESAJLAR.Where(p => p.SENDERID == id || p.SENTID == id).OrderBy(p => p.DATE).GroupBy(p => p.SPECIALID).OrderBy(p => p.XXXXX).Select(p => p.Last()).ToListAsync();
And your first order would probably be not needed anymore.
I'v declared a var to select elements from db context named BUGS(Table).
i set it to include all the columns, there is a foreign key named ProjectsPId.
It can return the id (The foreign key), but it returns "null" if we call projects.name for example.
So, i declared a var ("BUGS1" = context.bugs) this give me the value of project.name with no problems.
How i can put the "Project Name" value from the var bugs1 to the var bugs.
i'v tried to do this:
bugs.Where(b => b.Projects.PName) = bugs1.Where(c => c.Projects.PName);
this give me an error
public async Task<IActionResult> Index(int? id, string sortOrder, string searchString)
{
var bugs1 = _context.BugsSummary;
var bugs = from b in _context.BugsSummary
select b;
{
if (!String.IsNullOrEmpty(searchString))
{
bugs = bugs.Where(b => b.Projects.PName.Contains(searchString)
|| b.Bug.Contains(searchString));
}
switch (sortOrder)
{
case "name_desc":
bugs = bugs.OrderByDescending(b => b.Projects.PName);
break;
case "Date":
bugs = bugs.OrderBy(b => b.PublicationDate);
break;
case "date_desc":
bugs = bugs.OrderByDescending(b => b.PublicationDate);
break;
default:
bugs = bugs.OrderBy(b => b.Projects.PName);
break;
}
if (id > 0)
{
bugs.Include(b => b.User).Include(b => b.Projects)
.Where(b => b.ProjectsPId == id)
;
}
else
{
bugs.Include(b => b.User).Include(b => b.Projects);
}
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["CurrentFilter"] = searchString;
}
bugs.Where(b => b.Projects.PName) = bugs1.Where(c => c.Projects.PName);
return View(await bugs.AsNoTracking().ToListAsync());
}
When you set the initial value of the query, you need to use Include method to load related data like below :
var bugs = from b in _context.BugsSummary.Include(b=>b.Projects)
select b;
Then you don't need bug1 to pass the value of the string "project.name" to bugs
I have a Member table which has a foreign key from ASPNETUSERS table. My ASPNETUSERS table has additional fields in it for First Name and Last Name which I would like to use as sort values in my Members Controller.
var members = from m in db.Members.Include(m => m.AspNetUser).Include(m => m.Location) select m;
This is currently the initial query i am retrieving to get me all the members and searching is easy as i can use the following syntax.
members = members.Where(m => m.AspNetUser.LastName.Contains(searchString)
|| m.AspNetUser.HomePhone.Contains(searchString)
|| m.AspNetUser.MobilePhone.Contains(searchString)
|| m.AspNetUser.FirstName.Contains(searchString)
|| m.IdentificationNumber.Contains(searchString));
However when i try to do my sorting e.g.
members = members.OrderByDescending(m => m.AspNetUser.LastName);
It "works" however it doesn't actually sort but the Last name of the related table.
Can someone advise me as to what I am doing wrong.
Thank you.
Update: Below is full Action Result Method.
public ActionResult Index(string sortOrder, string searchString, string Command)
{
//Redirect back to login page if not authenticated
if (!HttpContext.User.Identity.IsAuthenticated)
{
return RedirectToAction("Login", "Account");
}
ViewBag.LastNameSortParm = String.IsNullOrEmpty(sortOrder) ? "lastname_desc" : "";
ViewBag.FirstNameSortParm = sortOrder == "firstname" ? "firstname_desc" : "firstname";
var members = from m in db.Members.Include(m => m.AspNetUser).Include(m => m.Location) select m;
if (Command == "Search")
{
if (!String.IsNullOrEmpty(searchString))
{
members = members.Where(m => m.AspNetUser.LastName.Contains(searchString)
|| m.AspNetUser.HomePhone.Contains(searchString)
|| m.AspNetUser.MobilePhone.Contains(searchString)
|| m.AspNetUser.FirstName.Contains(searchString)
|| m.IdentificationNumber.Contains(searchString));
}
}
else if (Command == "Reset")
{
}
switch (sortOrder)
{
case "lastname_desc":
members = members.OrderByDescending(m => m.AspNetUser.LastName);
break;
case "firstname":
members = members.OrderBy(m => m.AspNetUser.FirstName);
break;
case "firstname_desc":
members = members.OrderByDescending(m => m.AspNetUser.FirstName);
break;
default:
members = members.OrderBy(m => m.AspNetUser.LastName);
break;
}
return View(members.ToList());
}
I have this code but it doesn't work :
public bool DeleteAccess(int _UserID, IEnumerable<int> _ModulID)
{
MPortalContext db=new MPortalContext();
foreach (var item in _ModulID)
{
var validation = db.WebSite_PermissionDB.Where(x => x.UserID == _UserID && x.ModuleID == item);
db.WebSite_PermissionDB.Remove(validation);
}
db.SaveChanges();
return true;
}
my (_ModulID) is a collection of ids that i filter them and then with foreach delete them but it doesn't work ??
one way to delete is
context.Database.SqlQuery<WebSite_PermissionDB>(
"DELETE FROM Users WHERE UserID = #userId ",
new [] { new SqlParameter("#userId ", 1) }
);
First get the all entities that mathces with your condition, then use RemoveRange method:
var entities = db.WebSite_PermissionDB
.Where(x => x.UserID == _UserID && _ModulID.Contains(x.ModuleID));
db.WebSite_PermissionDB.RemoveRange(entities);
db.SaveChanges();
Also you might want to use using statement in order to make sure that your DbContext is Disposed properly.
using(MPortalContext db = new MPortalContext())
{
...
}
var distinctResult = db.WebSite_PermissionDB.Distinct();
db.WebSite_PermissionDB.RemoveRange(db.WebSite_PermissionDB.Except(distinctResult));
db.SaveChanges();
MPortalContext db=new MPortalContext();
foreach (var item in _ModulID)
{
var validation = db.WebSite_PermissionDB.Where(x => x.UserID == _UserID && x.ModuleID == item).FirstOrDefault();
db.WebSite_PermissionDB.Remove(validation);
db.SaveChanges();
}
return true;
I forget use .FirstOrDefault(); now correct. Thank friends.
Here's my query for retrieving list of inactive/active users from my database. my problem is that, my query seems to be too complicated. so can you please give me a tip how to enhance my query.
here's my code
using (basecampcoreEntities dbs = ConfigAndResource.BaseCampContext())
{
//loads all user where isactive property has the same value as IsActive
var Users = from useritem in dbs.users
where useritem.useraccount.IsActive.Equals(IsActive)
orderby useritem.useraccount.CreatedDate
select useritem;
//check if users count is greater than 0
if (Users.Count() > 0)
{
List<user> CasebookUser = new List<user>();
switch (SearchBy)
{
case DTO::SearchBy.FirstName:
{
CasebookUser = Users.Where(item => item.FirstName.ToUpper().Equals(SearchText.ToUpper())).Skip(skip).Take(take).ToList();
} break;
case DTO::SearchBy.LastName:
{
CasebookUser = Users.Where(item => item.LastName.ToUpper().Equals(SearchText.ToUpper())).Skip(skip).Take(take).ToList();
} break;
case DTO::SearchBy.LoginID:
{
CasebookUser = Users.Where(item => item.LoginID.ToUpper().Equals(SearchText.ToUpper())).Skip(skip).Take(take).ToList();
} break;
case DTO::SearchBy.None:
CasebookUser = Users.Skip(skip).Take(take).ToList();
{
} break;
}
//transform the data into DTO class
return (from item in CasebookUser
select new DTO::User
{
LoginID = item.LoginID,
FirstName = item.FirstName,
LastName = item.LastName,
MiddleName = item.MiddleName,
Birhtday = item.userinfo != null ? item.userinfo.Birthday : DateTime.UtcNow
}).ToList();
}
return null;
Leverage the power of delayed execution here...
// first filter by whether user is active or not
var query = dbs.users.Where(x => x.useraccount.IsActive == IsActive);
// next filter by specific search field
switch (SearchBy)
{
case DTO::SearchBy.FirstName:
{
query = query.Where(x => string.Equals(x.FirstName, SearchText, StringComparison.InvariantCultureIgnoreCase));
break;
}
case DTO::SearchBy.LastName:
{
query = Users.Where(x => string.Equals(x.LastName, SearchText, StringComparison.InvariantCultureIgnoreCase));
break;
}
...
}
// then apply paging
query = query.Skip(skip).Take(take);
// finally, order by CreatedDate (ascending)
query = query.OrderBy(x => x.useraccount.CreatedDate);
// now fetch the records!
return (from item in query
select new DTO::User
{
LoginID = item.LoginID,
FirstName = item.FirstName,
LastName = item.LastName,
MiddleName = item.MiddleName,
Birhtday = item.userinfo != null ? item.userinfo.Birthday : DateTime.UtcNow
}).ToList();
This code will give you what you need in a more optimal way (only 1 DB trip) - and it's a bit more readable into the bargain.
I would:
Remove the sort from the original query definition
Do not convert ToList() and to Skip()' andTake()` prematurely
Do not cast ToList() twice. Only do it when you are creating your final collection.
Make IsActive comparison more clear in the initial query
Rewrite first query as one line linq expression
Use Any() instead of Count() > 0
Convert your search text ToUpper() just one time. Makes your search cases more concise and readable (same with using == instead of Equals)
This code might help:
using (basecampcoreEntities dbs = ConfigAndResource.BaseCampContext())
{
//loads all user where isactive property has the same value as IsActive
var Users = db.Users.Where(x => x.useraccount.IsActive == IsActive);
if (Users.Any())
{
var searchText = SearchText.ToUpper();
switch (SearchBy)
{
case DTO::SearchBy.FirstName:
Users = Users.Where(item => item.FirstName.ToUpper() == searchText);
break;
case DTO::SearchBy.LastName:
Users = Users.Where(item => item.LastName.ToUpper() == searchText);
break;
case DTO::SearchBy.LoginID:
Users = Users.Where(item => item.LoginID.ToUpper() == searchText);
break;
}
// apply sort and skip/take
Users = Users.OrderBy(x => x.useraccount.CreateDate).Skip(skip).Take(take);
//transform the data into DTO class
return (from item in Users
select new DTO::User
{
LoginID = item.LoginID,
FirstName = item.FirstName,
LastName = item.LastName,
MiddleName = item.MiddleName,
Birthday = item.userinfo != null ? item.userinfo.Birthday : DateTime.UtcNow
}).ToList();
}
return null;
}