Linq to Entities orderby parent table value. (MVC) - c#

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

Related

Calling query inside query in entity framework core

I want to do something like this
public string GetSiteTitleFromChangeHistory(int siteId)
{
var changeHistories = changeHistoryRepository.GetAll(c => c.SiteRegistryId == siteId);
var value = changeHistories.firstOrDefault(r=>r.State="Active")
return value.Title;
}
public IQueryable<PendingReconfirmation> GetSitesForBusinessReconfirmationReminder(IList<StateStatus> stateStatusMappingIds,
string country, int reminderDay)
{
return from reg in repositorySpositeRegistry.GetAll(x => x.SiteUrlcountryCode != null
&& x.SiteUrlcountryCode.ToLower() == country.ToLower())
select new PendingReconfirmation()
{
Id = reg.Id,
SiteTitle = GetSiteTitleFromChangeHistory(reg.Id!).ToString() ?? reg.SiteTitle,
};
}
Repository.GetAll look like this
public IQueryable<T> GetAll(Expression<Func<T, bool>>? filter = null)
{
var query = entities.AsQueryable();
if (filter != null)
query = query.Where(filter);
return query;
}
But I am getting error
The client projection contains a reference to a constant expression of '' through the instance method 'GetSiteTitleFromChangeHistory'. This could potentially cause a memory leak; consider making the method static so that it does not capture constant in the instance.
Any help will be highly appreciated
Make this function GetSiteTitleFromChangeHistory as STATIC.
Is there a specific reason you split up GetSiteTitleFromChangeHistory into a separate method?
Otherwise you should be able to do a subquery like so, provided the queryable used for the subquery is based on a dbset in the same efcontext:
public IQueryable<PendingReconfirmation> GetSitesForBusinessReconfirmationReminder(IList<StateStatus> stateStatusMappingIds,
string country, int reminderDay)
{
return from reg in repositorySpositeRegistry.GetAll(x => x.SiteUrlcountryCode != null
&& x.SiteUrlcountryCode.ToLower() == country.ToLower())
select new PendingReconfirmation()
{
Id = reg.Id,
SiteTitle = changeHistoryRepository.GetAll(c => c.SiteRegistryId == reg.Id && c.State == "Active").FirstOrDefault().Title ?? reg.Title
};
}

how to put a string value from one Application Db Context to another?

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

Sort a Table on the Details Page

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.

Dynamic table name in Entity Framework

I am using Entity Framwork with a database-first approach. I want to change the table name or view name dynamically based on conditions.
Here, I am using V_OVT_VLD_340B_DNA_CLD or V_OVT_B_table or V_OVT_c_table to get the records.
Based upon the source, I need to call the different table name and get the records. The whole code snippet is the same, except for the table name.
Please refer below code
private dOVT_OutlierViewEntities db = new dOVT_OutlierViewEntities();
if(source == "a")
{
var result = this.db.V_OVT_VLD_340B_DNA_CLD.Where(x => x.DNA_PGM_PRTN_ID == partitionId && x.CLIENT_ID == clientId).ToList().Select(y => new ValidationModel
{
claim_validation_test_id = new List<byte?> { y.CLAIM_VLD_TEST_ID },
claim_id = y.CLAIM_ID,
Provider_ID = y.Provider_ID,
}).Take(id).ToList();
}
if(source == "b")
{
var result = this.db.v_OVT_B_table.Where(x => x.DNA_PGM_PRTN_ID == partitionId && x.CLIENT_ID == clientId).ToList().Select(y => new ValidationModel
{
claim_validation_test_id = new List<byte?> { y.CLAIM_VLD_TEST_ID },
claim_id = y.CLAIM_ID,
Provider_ID = y.Provider_ID,
}).Take(id).ToList();
}
if(source == "c")
{
var result = this.db.v_OVT_C_table.Where(x => x.DNA_PGM_PRTN_ID == partitionId && x.CLIENT_ID == clientId).ToList().Select(y => new ValidationModel
{
claim_validation_test_id = new List<byte?> { y.CLAIM_VLD_TEST_ID },
claim_id = y.CLAIM_ID,
Provider_ID = y.Provider_ID,
}).Take(id).ToList();
}
I want to modify the above implementation by dynamically attaching the table name to db context based upon condition.
string tableName = string.empty
if(source == "a")
tableName = "aTable";
if(source == "b")
tableName="bTable";
this.db.tableName.where().....
Is that possible?
You can go with a switch condition to set the table type and use that with context
switch (tableName)
{
case "a":
tableType = typeof(V_OVT_VLD_340B_DNA_CLD);
break;
case "b":
tableType = typeof(v_OVT_B_table);
break;
default:
tableType = typeof(v_OVT_C_table);
break;
}
var query = context.Set(tableType);
var result = query.Find(); //filter with this query condition
You can do something like this..
string tableName = string.empty
if(source == "a")
tableName =db.GetTable("aTable");
if(source == "b")
tableName=db.GetTable("bTable");
and then query like..
tableName.where()

LINQ IQueryable Query

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;
}

Categories

Resources