LINQ equivalent of SQL NOT IN statement - c#

I have a query that in T-SQL it is
SELECT *
FROM rpm_scrty_rpm_usr ru
WHERE ru.inact_ind = 'N'
AND email_id IS NOT NULL
AND wwid IS NULL
AND LTRIM(RTRIM (email_id)) <> ''
AND dflt_ste_id NOT IN (25,346,350,352,353,354,355,357,358,366,372,411)
When I have been converting it to LINQ, I have everything except the "NOT IN"
var querynonSystem = (from ru in Rpm_scrty_rpm_usrs
where ru.Inact_ind == "N" && ru.Email_id != null && ru.Wwid == null && ru.Email_id.Trim() != ""
&& ru.Dflt_ste_id != 25
select ru).Count();
I did temporarily put in this line && ru.Dflt_ste_id != 25
However I need to have AND dflt_ste_id NOT IN (25,346,350,352,353,354,355,357,358,366,372,411)
I am seeing a lot of different code like
this lambda where !(list2.Any(item2 => item2.Email == item1.Email))
Then var otherObjects = context.ItemList.Where(x => !itemIds.Contains(x.Id));
For my linq query, how can I do this Not In in simple manner?

You can use Contains with !. In addition, if you just want to count rows, you can use Count.
var ids = new List<int> {25, 346, 350, 352, 353, 354, 355, 357, 358, 366, 372, 411};
var querynonSystem = XXXcontext.Rpm_scrty_rpm_usrs.Count(x =>
x.Inact_ind == "N" &&
x.Email_id != null &&
x.Wwid == null &&
x.Email_id.Trim() != "" &&
!ids.Contains(x.Dflt_ste_id));
From comment: if you want to retrieve all, you can still use Where and Select.
var querynonSystem = XXXcontext.Rpm_scrty_rpm_usrs.Where(x =>
x.Inact_ind == "N" &&
x.Email_id != null &&
x.Wwid == null &&
x.Email_id.Trim() != "" &&
!ids.Contains(x.Dflt_ste_id)).Select(x => x).ToList();
FYI: you cannot call Rpm_scrty_rpm_usrs table class to query. Instead, you need DbContext or some other repository.

There is no "not in" operator unless the type of the query is the same as the type you want to filter against (in which case you could use except). Here it is not. You're working on an IEnumerable and you want to filter on it's ID so a list of int. The where with lambda and contains is your best bet and WILL be translated to an in on the SQL side by most providers.
var FilterIds = new List<int>{1,2,3,4,344,3423525};
var querynonSystem = (from ru in Rpm_scrty_rpm_usrs
where ru.Inact_ind == "N" && ru.Email_id != null && ru.Wwid == null && ru.Email_id.Trim() != ""
&& ru.Dflt_ste_id != 25
select ru)
// Use this
.Where(ru=>!FilterIds.Any(id=>ru.dflt_ste_id ==id))
// Or this
.Where(ru=>!FilterIds.Contains(ru.dflt_ste_id))
.Count();

Related

C# Linq to EF Separate Subquery into Expression

I have a complex where clause in my EF linq statement which repeats a subquery expression, on _db.OPESRRecoveryElements, but with different parameters, one of which is depending on records from the main entity, OPCases/OPCaseDto.
The query as it is works, but its hard for people to read. Ideally I'd like to be able to create an expression which could be re-used at the 3 necessary points and would still allow it to execute as a single, server-side SQL statement.
Is there a way to create an Expression / IQueryable definition which can be used for a subquery like this?
List<OPCaseDto> opCases = await _db.OPCases
.ProjectTo<OPCaseDto>(_autoMapperConfig, null, requestedExpands)
.Where(c =>
c.OPStatusId == OPStatusIds.AwaitingRecoveryElement
&& (
(c.OPCategoryLetter == "B"
// Only need a gross pensionable element if there is an outstanding gross pensionable figure
&& (c.GrossOverpaidPensionable - c.GrossRecoveredPensionable == 0
|| _db.OPESRRecoveryElements.Any(e => !e.NonPensionable && e.OPRecoveryMethod.OPTypeLetter == "G"
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery)
&& rp.AssignmentNo == c.RecoveryAssignmentNo)))
// Only need a gross non-pensionable element if there is an outstanding gross non-pensionable figure
&& (c.GrossOverpaidNonPensionable - c.GrossRecoveredNonPensionable == 0
|| _db.OPESRRecoveryElements.Any(e => e.NonPensionable && e.OPRecoveryMethod.OPTypeLetter == "G"
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery)
&& rp.AssignmentNo == c.RecoveryAssignmentNo))))
|| (c.OPCategoryLetter == "D"
// Don't need to check for an outstanding net figure - if the case is net and isn't complete, there will be one!
&& _db.OPESRRecoveryElements.Any(e => e.OPRecoveryMethod.OPTypeLetter == "N"
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery)
&& rp.AssignmentNo == c.RecoveryAssignmentNo)))
)
)
.AsNoTracking()
.ToListAsync();
If it wasn't for the c.RecoveryAssignmentNo part, I could easily create an expression like:
public Expression<Func<OPESRRecoveryElement, bool>> NoActiveRecoveryPlans(string opType, bool nonPen)
{
return e => e.OPRecoveryMethod.OPTypeLetter == opType
&& e.NonPensionable == nonPen
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery));
}
and use it like:
(c.OPCategoryLetter == "B"
// Only need a gross pensionable element if there is an outstanding gross pensionable figure
&& (c.GrossOverpaidPensionable - c.GrossRecoveredPensionable == 0
|| _db.OPESRRecoveryElements.Any(NoActiveRecoveryPlans("G", false)))
and it would get executed before the query to get the OPCases.
I could also fetch all the OPCaseDto records and OPESRRecoveryElements as separate queries and filter in memory, but I don't want to do that.
If I add a parameter to the function, string assignmentNo, I (unsurprisingly) get an error - "Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpression3' to type 'System.Linq.Expressions.LambdaExpression'"

LINQ query automatic List Populate vs ToList in EF 6.1

I am using visual studio 2013 .Here a strange thing happen but i cannot find the answer .I have following LINQ query
var tvAssingedJobs = dbEntities.Tv_ProductService
.Where(i => i.ServiceManagerId == userId
&& i.TechnicianId != null
&& (i.ProductServiceStatus != "C"
&& i.ProductServiceStatus != "QP")
);
foreach (var assingedJob in tvAssingedJobs)
{
var requision = assingedJob.Tv_SparePartsRequision
.FirstOrDefault(i => i.RecommendedUserId == userId
&& i.TechnicianId == assingedJob.TechnicianId
);
}
Here i can iterate but i did not convert it to list .Is this query supposed to be like this
var tvAssingedJobs = dbEntities.Tv_ProductService
.Where(i => i.ServiceManagerId == userId
&& i.TechnicianId != null
&& (i.ProductServiceStatus != "C"
&& i.ProductServiceStatus != "QP")
).ToList();
Both working fine.So my question in which to use ? Is first query may cause exception or create some performance issue in production in future ?

How to check if object is null in EF

I am new to EF and trying to do a small project with it. I added a condition to EF but I am having a problem.
My condition is all about IN condition like SQL,
SELECT * FROM table1 WHERE col1 IN (1,2,3...)
Here is my EF....
var res3 = res2.Where(l => !slitDetail
.Any(s => s.BlockId == l.Id
&& s.WarehouseDepot.WarehouseDepotName != "Ara Ürün Depo"
&& s.WarehouseDepot.WarehouseDepotName != "Özel Kesim Depo"));
s.WarehouseDepot might be NULL sometimes which is normal, but if it is null, this query throws an exception.
How can I check if s.WarehouseDepot is null and make it work even if it is null?
There are 2 possiblities if s.WarehouseDepot == null
1) You want your Any to return true, in that case you could use something like
var res3 = res2.Where(l => !slitDetail
.Any(s => s.BlockId == l.Id
&& s.WarehouseDepot != null
? (s.WarehouseDepot.WarehouseDepotName != "Ara Ürün Depo" && s.WarehouseDepot.WarehouseDepotName != "Özel Kesim Depo")
: true));
This would use the s.WarehouseDepot only if it has a value otherwise it would return true
2) You want your Any to return false. In this case you could simply replace the true by false in the above expression or use something like
var res3 = res2.Where(l => !slitDetail
.Any(s => s.BlockId == l.Id
&& s.WarehouseDepot != null
&& s.WarehouseDepot.WarehouseDepotName != "Ara Ürün Depo"
&& s.WarehouseDepot.WarehouseDepotName != "Özel Kesim Depo"));
Note that both these outcomes will automatically consider the s.BlockId == l.Id condition too.

Using Linq to filter by List<ListItem>

I am trying to extend my linq query with additional search criteria to filter the data by sending also a List<Listitem> to the function for processing. The List can contain 1 or more items and the objective is to retreive all items which match any criteria.
Since i am sending several search criteria to the function the goal is to make a more accurate filter result the more information i am sending to the filter. If one or several criterias are empty then the filter will get less accurate results.
Exception is raised every time i execute following code, and I cant figure out how to solve the using statement to include the List<ListItem>. Appreciate all the help in advance!
Exception: Unable to create a constant value of type 'System.Web.UI.WebControls.ListItem'. Only primitive types or enumeration types are supported in this context.
using (var db = new DL.ENTS())
{
List<DL.PRODUCTS> products =
(from a in db.PRODUCTS
where (description == null || description == "" ||
a.DESCRIPTION.Contains(description)) &&
(active == null || active == "" || a.ACTIVE.Equals(active, StringComparison.CurrentCultureIgnoreCase)) &&
(mID == null || mID == "" || a.MEDIA_ID == mID) &&
(mID == null || objTypes.Any(s => s.Value == a.OBJECTS)) //Exception here!
select a).ToList<DL.PRODUCTS>();
return products;
}
Pass collection of primitive values to expression:
using (var db = new DL.ENTS())
{
var values = objTypes.Select(s => s.Value).ToArray();
List<DL.PRODUCTS> products =
(from a in db.PRODUCTS
where (description == null || description == "" || a.DESCRIPTION.Contains(description)) &&
(active == null || active == "" || a.ACTIVE.Equals(active, StringComparison.CurrentCultureIgnoreCase)) &&
(mID == null || mID == "" || a.MEDIA_ID == mID) &&
(mID == null || values.Contains(a.OBJECTS))
select a).ToList<DL.PRODUCTS>();
return products;
}
That will generate SQL IN clause.
Note - you can use lambda syntax to compose query by adding filters based on some conditions:
var products = db.PRODUCTS;
if (!String.IsNullOrEmpty(description))
products = products.Where(p => p.DESCRIPTION.Contains(description));
if (!String.IsNullOrEmpty(active))
products = products.Where(p => p.ACTIVE.Equals(active, StringComparison.CurrentCultureIgnoreCase)));
if (!String.IsNullOrEmpty(mID))
products = products.Where(p => p.MEDIA_ID == mID);
if (mID != null)
products = products.Where(p => values.Contains(p.OBJECTS));
return products.ToList();
Linq isn't able to convert the predicate on ListItem to something useful to Sql.
I would suggest that you pre-project the values of the ListItems into a simple List<string> before using this with Contains (which is converted to IN)
var listValues = objTypes.Select(_ => _.Value).ToList();
List<DL.PRODUCTS> products = ...
listValues.Contains(a.OBJECTS))

Linq parser issue?

Well,
I am not sure if I am wrong or if the linq parsed mistakes, but the following linq query returns what I DON'T want if I don't use additional parenthesis.
int? userLevel;
Guid? supervisorId;
List<int> levelsIds = new List<int>();
string hierarchyPath;
// init the vars above
// ...
var qry = from f in items
where userLevel.HasValue
? (f.IsMinLevelIdNull() || (levelsIds.Contains(f.MinLevelId)))
: true
&& supervisorId.HasValue
? (f.IsSupervisorIdNull() || (!f.ChildrenVisibility && (f.SupervisorId == supervisorId.Value))
|| (f.ChildrenVisibility && (hierarchyPath.IndexOf(f.SupervisorId.ToString()) >= 0)))
: true
select f;
The idea here is to run a query in AND between two blocks of conditions 'activated' by the presence of the variables 'userLevel' and 'supervisorId'.
For example, if both userLevel and supervisoId are null the query becomes:
var qry = from f in items
where true && true
select f;
Well, this query works well only if I enclose in additional parentheses the 2 trigraphs:
var qry = from f in items
where (userLevel.HasValue
? (f.IsMinLevelIdNull() || (levelsIds.Contains(f.MinLevelId)))
: true)
&& (supervisorId.HasValue
? (f.IsSupervisorIdNull() || (!f.ChildrenVisibility && (f.SupervisorId == supervisorId.Value))
|| (f.ChildrenVisibility && (hierarchyPath.IndexOf(f.SupervisorId.ToString()) >= 0)))
: true)
select f;
The question is: why the extra parenthesis are required? My opinion is that there is a problem in the linq parser.
From 7.2.1 Operator precedence and associativity && gets evaluated before ? :
The additional parentheses would be required as the precedence is evaluated in the wrong order for example your code would be evaluated as the following because there is no break between true && supervisorId.HasValue...
var qry = from f in items
where
1st: userLevel.HasValue
?
2nd: (f.IsMinLevelIdNull() || (levelsIds.Contains(f.MinLevelId)))
:
3rd: true && supervisorId.HasValue
? (f.IsSupervisorIdNull() || (!f.ChildrenVisibility && (f.SupervisorId == supervisorId.Value))
|| (f.ChildrenVisibility && (hierarchyPath.IndexOf(f.SupervisorId.ToString()) >= 0))) **)**
: true
select f;

Categories