LINQ query using Contains and conditional logic - linq

I have 4 textboxes that are used for searching registered users.
Lastname, Firstname, SSN, County
I'm trying to make my LINQ query so that all 4 values are in my WHERE clause and the results drilldown each time the user enters data in another textbox. The query needs to be able to handle empty string or ""
For example, there are 500 registered users. The user enters Smith in the LastName textbox and of the 500, there are 20 Smith users.
Now the user enters Smith for LastName and John for FirstName. The query returns 5 Smith, John of the 500.
Now the user enters Smith for LastName and John for FirstName and Fulton for County. The query returns 1 user.
How can I modify this query to drilldown when the end user searches for a registered user?
var query = _context.User
.Where(r => r.LastName.ToUpper().Contains(lastname.ToUpper())
|| r.FirstName.ToUpper().Contains(FirstName.ToUpper())
|| r.County.ToUpper().Contains(County.ToUpper())
|| r.SSN.ToUpper().Contains(SSN.ToUpper()));
var results = query
.OrderBy(x => x.LastName)
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToList();

Switch your ORs to ANDs and only include the check if there is a value:
var query = _context.User
.Where(r =>
(string.IsNullOrEmpty(lastname) || r.LastName.ToUpper().Contains(lastname.ToUpper())))
&& (string.IsNullOrEmpty(FirstName) || r.FirstName.ToUpper().Contains(FirstName.ToUpper()))
&& (string.IsNullOrEmpty(County) || r.County.ToUpper().Contains(County.ToUpper()))
&& (string.IsNullOrEmpty(SSN) || r.SSN.ToUpper().Contains(SSN.ToUpper()))
);

try this query,
var query = _context.User
.Where(r => (r.LastName.ToUpper().Contains(lastname.ToUpper()) && lastname!=null)
|| (r.FirstName.ToUpper().Contains(FirstName.ToUpper()) && FirstName!=null)
|| (r.County.ToUpper().Contains(County.ToUpper()) && County != null)
|| (r.SSN.ToUpper().Contains(SSN.ToUpper()) && SSN!=null));

Related

Transform Sql to EF Core Linq query

I am trying to translate the following query from SQL to EF Core. I can easily just use a stored procedure (I already have the SQL), but am trying to learn how some of the linq queries work. Unfortunately this is not by any means an ideal database schema that I inherited and I don't have the time to convert it to something better.
DECLARE #userId INT = 3
SELECT *
FROM dbo.CardGamePairs
WHERE EXISTS (SELECT 1
FROM dbo.Users
WHERE Users.Id = CardGamePairs.player1Id
AND Users.userId = #userId)
UNION
SELECT *
FROM dbo.CardGamePairs
WHERE EXISTS (SELECT 1
FROM dbo.Users
WHERE Users.Id = TableB.player2Id
AND Users.userId = #userId)
So basically I have an id that can exist in one of two separate columns in table b and I don't know in which column it may be in, but I need all rows that have that ID in either column. The following is what I tried to make this work:
//Find data from table A where id matches (part of the subquery from above)
var userResults = _userRepository.GetAllAsQueryable(x => x.userId == userId).ToList();
//Get data from table b
var cardGamePairsResults = _cardGamePairsRepository.GetAllAsQueryable(x => userResults .Any(y => y.userId == x.player1Id || y.userId == x.player2Id));
When I run the code above I get this error message:
predicate: (y) => y.userId == x.player1Id || y.userId == x.player2Id))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
Any ideas on how I can make this work? (I tried changing the column and table names to something that would actually make sense, hopefully I didn't miss any spots and make it more confusing.)
Because you are already have user id use it to query both columns.
var userResults = _userRepository
.GetAllAsQueryable(x => x.userId == userId)
.ToList();
var cardGamePairsResults = _cardGamePairsRepository
.GetAllAsQueryable(x => x.player1Id == userId || x.player2Id == userId));

BETWEEN operator for string in LINQ to SQL query

from p in table
where ID == 201
&& date => 20160601
&& date <= 20160901
select {ID, name};
q.Dump();
The date in the database is in string simple format.
I am trying to convert a SQL query to LINQ. In SQL, BETWEEN operator is being used to select values within a given range. But, BETWEEN can't be used with LINQ statement, so I am getting an error which says => cannot be applied to operands of type string and int for the date field. Any help would be appropriated. I tried the DateTime, but it didn't work for me.
Since LINQ to Entities doesn't support Convert.ToDateTime (why not?) and your date formats are in a reasonable string format, you can compare as strings:
from p in table
where ID == 201
&& date.CompareTo("20160601") >= 0
&& date.CompareTo("20160901") <= 0
select { ID, name };
Try this working code:
var q = from p in table
where p.ID == 201
&& p.date >= DateTime.ParseExact("20160601", "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture)
&& p.date <= DateTime.ParseExact("20160901", "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture)
select p;
q.Dump();

Linq join get null rows filter with where

I have three tables joined. Store, StoreReport and Report.
Store table
StoreId
Storename.
Report table
ReportId
ReportName
StoreReport table
StoreId
ReportId
I would like to get all the Stores that haven't filled in a specific report.
So far I have this but it counts those who are connected to other reports also.
var reports = from u in db.tblStores
join sr in db.tblStoreReports.Where(a => a.ReportId != reportId && !a.Deleted)
on u.StoreId equals sr.StoreId into g
where !g.Any()
select u;
from u in db.tblStores
where !u.StoreReports.Any(a => a.ReportId == reportId && !a.Deleted)
select u
You can use !.Any to make sure it does not have a Report with certain id
Isn't it simpler? You can use Where without a join:
var reports = from u in db.tblStores
where !db.tblStoreReports.Any(sr => sr.StoreId == u.StoreId
&& sr.ReportId == reportId
&& !sr.Deleted)
select u;

Sorting issue with LINQ query and join using tables from different databases

I'm having trouble writing my LINQ query.
Here's the scenario:
I have 2 databases: A and B
In database A: I have a tableX which has the following fields: Employee ID, Name, Address, Phone, ..., Active
In database B: I have a tableY which has the following fields: Employee ID, Visible, Order
the number of records in table Y is less than or equal to the number of records in table X.
Basically, I need to extract the employee records from table X who have the attribute 'Visible' (in table Y) set to True and would like to sort them using the 'Order' attribute.
This is what I have so far:
ADataContext dbA = new ADataContext();
BDataContext dbB = new BDataContext();
//Get the list of records from tableY where 'Visbile' is set to True
var List = dbB.tableY
.Where(x => x.Visible == true).OrderBy(x => x.Order)
.ToList();
//Extract the list of employee IDs
IEnumerable<int> ids = List.Select(x => x.EmployeeID).Distinct();
var employees = dbA.tableX
.Where(x => ids.Contains(x.EmployeeID) && x.Active == true)
.ToList();
I'm able to get the correct list of employees, but cannot figure out how to apply the sorting order (present in tableY) on tableX
Currently, regardless of the order specified in tableY, the records returned from tableX are sorted as they were entered in the table (oldest to most recent).
Any ideas how I can fix my query.
Thanks,
I've re-written it all as a single query:
var employees =
from x in dbA.tableX
where x.Active
from y in dbB.tableY
where x.EmployeeID == y.EmployeeID
orderby y.Order
select x;

LINQ Select Row with Max date per group

I want to return all the values from my "Categories" table and join that to my "CategorySelections" table to display all the categories and whether the specified user selected them or not.
A complication (which I don't know how to deal with in LINQ) is that the user could have changed his selection/deselection of a particular category over time...each change would have logged in the "CategorySelections" table with a date stamp.
I am after the last selection status.
The following SQL query does what I want:
SELECT cs.UserId, c.CategoryId, m.MaxDate, cs.IsSelected
FROM [myDB].[dbo].[Categories] c
LEFT JOIN [myDB].[dbo].[CategorySelections] cs
ON c.CategoryID = cs.CategoryID AND cs.UserID = 7
INNER JOIN
(
SELECT UserId, CategoryId, Max(CreatedOn) as MaxDate
FROM [myDB].[dbo].[CategorySelections]
GROUP BY UserId, CategoryId
) m
ON cs.UserID = m.UserID AND cs.CategoryID = m.CategoryID AND cs.CreatedOn = m.MaxDate
ORDER BY cs.CategoryI
I need some help getting this done in LINQ.
Below is my attempt, which returns all the selections instead of just the last per category.
var query = from c in db.Category
join cs in db.CategorySelection.Where(x => x.UserID == WebSecurity.CurrentUserId)
on c.CategoryID equals cs.CategoryID into JoinedCategory
from cs in JoinedCategory.DefaultIfEmpty()
select new Selection() { CategoryID = c.CategoryID, CategoryName = c.CategoryName ,IsSelected = cs != null ? cs.IsSelected : false }
I am working in MVC; the "new Selection()" refers to my Model
You may add WHERE statement:
where cs.CreatedOn == CategorySelections.Where(t => t.CategoryId == cs.CategoryId).Max(r => r.CreatedOn)

Resources