LINQ to SQL - WHERE clause filtered - linq

Why is the where condition not applied in the following code? When I search, the results are not getting filtered. When I debug, searchString does have a value and execution is going through the _data.Where clause but it's not returning the filtered result.
What I'm doing wrong here?
IQueryable<UserViewModel> _data = (
from a in context.aspnet_Users
join b in context.aspnet_Membership on a.UserId equals b.UserId
where b.IsApproved == true
select new UserViewModel
{
UserId = a.UserId,
UserName = a.UserName,
FirstName = a.FirstName,
LastName = a.LastName,
EmailAddress = b.Email
})
.OrderBy(a => a.FirstName)
.ThenBy(b => b.LastName);
if (!String.IsNullOrEmpty(searchString))
{
_data = _data
.Where(x => x.FirstName.Contains(searchString))
.Where(y => y.UserName.Contains(searchString))
.Where(y => y.LastName.Contains(searchString))
.Where(y => y.EmailAddress.Contains(searchString));
}

The way the second query is written checks for records where all filtered fields start with the search string, ie for users whose FirstName and LastName and UserName and Email all start with the same string.
I think what you wanted was a query that check whether any of these fields starts with the search string, eg:
_data = _data.Where(x => x.FirstName.Contains(searchString) ||
x.UserName.Contains(searchString) ||
x.LastName.Contains(searchString) ||
x.EmailAddress.Contains(searchString));

I suspect this is doing a lot more "filtering" than you expect:
_data = _data.Where(x => x.FirstName.Contains(searchString))
.Where(y => y.UserName.Contains(searchString))
.Where(y => y.LastName.Contains(searchString))
.Where(y => y.EmailAddress.Contains(searchString));
This requires that searchString exist in all four of those fields. So if you search for, say, "David" then it's going to fail to find my record because my LastName doesn't contain that string.
Perhaps you wanted to use a logical or instead of a logical and? Something like this:
_data = _data.Where(x => x.FirstName.Contains(searchString) ||
x.UserName.Contains(searchString) ||
x.LastName.Contains(searchString) ||
x.EmailAddress.Contains(searchString));

Related

Where in clause using linq

trying to convert a query which has 2 levels of where in clauses to linq and getting some errors. Can anybody help me on this?
Original Query:
select id
from student
where suId
in (select suId
from subjects
where cid
in (select id
from chapters
where chapter='C203'))
LINQ query:
var query = (from s in dc.students
let subs = (from su in dc.subjects
where su.cid == Convert.ToInt32(from c in dc.Chapters
where c.chapter == 'Ç203'
select c.id) //Single chapter id will be returned
select su.suid)
where subs.Contains(s.sid)
select s.id).ToArray();
Am getting below 2 errors while compiling app
'System.Linq.IQueryable' does not contain a definition for 'Contains' and the best extension method overload 'System.Linq.ParallelEnumerable.Contains(System.Linq.ParallelQuery, TSource)' has some invalid arguments
Instance argument: cannot convert from 'System.Linq.IQueryable' to 'System.Linq.ParallelQuery'
Since Linq is lazy-loading everything you don't need to cram everything into a single statement; you can do something like this:
var chapterIds = dc.Chapters
.Where(c => c.Chapter == "C023")
.Select(c => c.Id);
var subjectIds = dc.Subjects
.Where(s => chapterIds.Contains(s.Cid))
.Select(s => s.Suid);
var students = dc.Students
.Where(s => subjectIds.Contains(s.Suid))
.Select(s => s.Sid)
.ToArray();
This way you can debug each subquery by looking at what it returns.
However, looking at your original select you can rewrite the whole thing as a Join and get rid of the bugging issue:
var students = dc.Chapters.Where(c => c.Chapter == "C023")
.Join(dc.Subjects,
c => c.Id,
s => s.Cid,
(chapter, subject) => subject)
.Join(dc.Students,
subj => subj.Suid,
student => student.Suid,
(subj, st) => st.Sid)
.ToArray();

Get distinct value from database

I want to get the distinct list of studentname from the database who are still active. Ihis is what I've tried.
string strJSON = JsonConvert.SerializeObject(
context.Students.Where(x => x.IsActive == 1).Distinct().ToList());
Distinct function works on all columns, so I assume that you want only student name.
string strJSON = JsonConvert.SerializeObject(
context
.Students
.Where(x => x.IsActive==1)
.Select(x=>x.StudentName)
.Distinct()
.ToList()
);

Getting the Error in my code when framing LINQ

My Code:
var lastName = employees
.Where(a => a.Number ==
(dm.MTM.Where(b => b.MTT.IsManager)
.Select(c => c.Number)
.FirstOrDefault()))
.Select(z => z.LastName)
.FirstOrDefault();
Error Message:
Unable to create a constant value of type 'XXX.Models.Mt.MTM'. Only primitive types or enumeration types are supported in this context.
Try:
int? num = dm.MTM.Where(b => b.MTT.IsManager).Select(c => c.Number).FirstOrDefault();
var lastName = employees.Where(a => a.Number == num).Select(z => z.LastName).FirstOrDefault();
But you should add a check
if (num == null)
{
// bad things, don't execute second query
}
between the two instructions.
The error is because in an Entity Framework query you can't do "things" too much fancy, like the things necessary to calculate num.
Try:
// Calculate the number outside of the main query
// because the result is fixed
var nb = dm.MTM
.Where(b => b.MTT.IsManager)
.Select(c => c.Number)
.FirstOrDefault();
// Perform the main query with the number parameter already calculated before
string lastName = String.Empty;
if (nb != null) // if null no need to run the query
{
lastName = employees
.Where(a => a.Number == nb)
.Select(z => z.LastName)
.FirstOrDefault();
}
You don't need to get the number from the database for each employee, calculate the value before running your main query.
This will be faster, less error-prone and better for caching.

LINQ: Drill down to value in query results

I am using LINQ for the first time and have the following query:
var query = from c in context.Call
join d in context.CallData on c.CallID = d.CallID
where c.CallID == 123
select new {
c.CallID,
c.CallResult,
d.FieldID,
d.FieldValue
};
This returns data similar to the following
c.CallID c.CallResult d.FieldID d.FieldValue
123 Sale 345 John
123 Sale 346 Doe
123 Sale 347 888-222-3333
How can drill down to the row containing d.FieldID = 346 to get the value of d.FieldValue (346 being the LastName field)? I would like to use this value as the new value of a local variable:
// I know this doesn't work, just showing what I would like to accomplish
string LastName = query.Select(a => a.FieldID = 346).FieldValue;
Conversely, how can I change the value of c.CallResult once I have these results? Since it is a join, can I simply change one row of data or do I have to do a separate query?
For the first question you can move on from your query variable:
var fieldValue = query.Where(x => x.FieldID == 346).Single().FieldValue;
As for your second question: you must apply a change to the original entity object:
var call = context.Find(123);
// or context.Calls.Single(c => c.CallId == 123) if this is not DbContext.
call.CallResult = newValue;
context.SaveChanges();
Do you mean:
string LastName = query
.Where(a => a.FieldID = 346)
.Select(a => a.FieldValue)
.FirstOrDefault();

Pivot in LINQ using lambda expression

I am writing a lambda in linq for getting the pivoted data from the resulting list.For getting the pivoting columns am setting a where condion to get the value.the problem here is am getting default value if the where condtion fails.I dont want the column if the where condition fails.Kindly help me out.
var query = dataList
.GroupBy(c => c.IpAddress)
.Select(g => new
{
IPAddress = g.Key,
AssetType = g.ElementAtOrDefault(0).AssetTypeName,
AssetName = g.ElementAtOrDefault(0).AssetName,
//if where condition fails i dont need this column.
//also am giving c.DsName == "Active Calls" ,how to achieve tis dynamically
**ActiveCalls = g.Where(c => c.DsName == "Active Calls").Sum(c => c.CurrentValue),**
**HoldCalls = g.Where(c => c.DsName == "Hold Calls").Sum(c => c.CurrentValue),**
**CPU = g.Where(c => c.DsName == "CPU").Sum(c => c.CurrentValue),**
});
Why not just create a value to hold the sum and then specify its a type in another column. That way you don't have to deal with null columns. (The assumption is that only one type is valid at a time).
Value = g.Sum(c => c.CurrentValue), // Value as specified by the the DsName property.
DsName = c.DsName

Resources