i have this query:
var TheQuery = db.Conventions.Where(p =>
p.Participants.Select(q => q.intituleParticipant).Contains(s));
and I need to add other conditions...
How is it possible to do it?
Put this in your query ||
or --> ||
var TheQuery = db.Conventions.Where(p => p.Participants.Select(q => q.intituleParticipant).Contains(s) || other conditions);
Pretty much the same way you'd add another condition in regular C#, by using the || (OR) operator.
var TheQuery = db.Conventions.Where(p =>
p.Participants.Select(q => q.intituleParticipant).Contains(s) ||
othercondition);
You want the || operator, same as you would use in an if statement.
Related
var itemInventoryUpdate2 = db.ItemInventoryDatas
.Single(items => items.ItemId == item.ItemId );
Hi How can I convert above code so that I can pass to multiple arguments like it will select not just for Item Id but also for the location Id.
use AND operator.
var itemInventoryUpdate2 = db.ItemInventoryDatas.Single(items => items.ItemId == item.ItemId && items.LocationId == item.LocationId);
You can use boolean logical operators inside lambdas:
var itemInventoryUpdate2 = db.ItemInventoryDatas
.Single(items => items.ItemId == item.ItemId && items.LocationId == item.LocationId);
Also if you want to concatenate multiple AND conditions you can specify multiple Where clauses:
var itemInventoryUpdate2 = db.ItemInventoryDatas
.Where(items => items.ItemId == item.ItemId)
.Where(items => items.LocationId == item.LocationId)
.Single();
Currently I have a LINQ query like this:
var policy = snapshotDate == null
? await _dbContext.VPolicies
.Where(p => p.PolicyNumber.Trim().Equals(policyNumber))
.OrderByDescending(d => d.PolicyEffectiveDate)
.FirstOrDefaultAsync()
: await _dbContext.VPolicies
.Where(p => p.PolicyNumber.Trim().Equals(policyNumber)
&& (p.PolicyEffectiveDate <= snapshotDate && p.PolicyExpirationDate > snapshotDate))
.OrderByDescending(d => d.PolicyEffectiveDate)
.FirstOrDefaultAsync();
I would like to know if I can shorten it like this:
var policy = await _dbContext.VPolicies
.Where(p => p.PolicyNumber.Trim().Equals(policyNumber))
.Where(p => snapshotDate != null && (p.PolicyEffectiveDate <= snapshotDate && p.PolicyExpirationDate > snapshotDate))
.OrderByDescending(d => d.PolicyEffectiveDate)
.FirstOrDefaultAsync();
But this doesn't work and I would like to know how I can condition this LINQ query in a proper way and shorten them without using the terenary operator.
Thanks in advance.
Try this:
var policy = await _dbContext.VPolicies
.Where(p => p.PolicyNumber.Trim().Equals(policyNumber)
&& (snapshotDate == null ||
(p.PolicyEffectiveDate <= snapshotDate &&
p.PolicyExpirationDate > snapshotDate)))
.OrderByDescending(d => d.PolicyEffectiveDate)
.FirstOrDefaultAsync();
This query will apply conditions of PolicyEffectiveDate and PolicyExpirationDate if snapshotDate is not null otherwise only PolicyNumber condition will apply.
Seems like you want your condition to evaluate
snapshotDate == null || (p.PolicyEffectiveDate <= snapshotDate && p.PolicyExpirationDate > snapshotDate)
Which says, give all dates when snapshotDate is null, or within when it's not.
Note : about multiple where clauses. In a memory based collection you are will get a performance increase combining them with an && (due to the extra delegate invocation, and potential multiple enumerations), however with most LINQ to Query providers it will evaluate in the exact same SQL. Though in general it's best combining these if you can.
I'm trying to recreate this SQL query in LINQ:
SELECT *
FROM Policies
WHERE PolicyID IN(SELECT PolicyID
FROM PolicyRegister
WHERE PolicyRegister.StaffNumber = #CurrentUserStaffNo
AND ( PolicyRegister.IsPolicyAccepted = 0
OR PolicyRegister.IsPolicyAccepted IS NULL ))
Relationship Diagram for the two tables:
Here is my attempt so far:
var staffNumber = GetStaffNumber();
var policyRegisterIds = db.PolicyRegisters
.Where(pr => pr.StaffNumber == staffNumber && (pr.IsPolicyAccepted == false || pr.IsPolicyAccepted == null))
.Select(pr => pr.PolicyID)
.ToList();
var policies = db.Policies.Where(p => p.PolicyID.//Appears in PolicyRegisterIdsList)
I think I'm close, will probably make two lists and use Intersect() somehow but I looked at my code this morning and thought there has to be an easier way to do this,. LINQ is supposed to be a more readble database language right?
Any help provided is greatly appreciated.
Just use Contains:
var policies = db.Policies.Where(p => policyRegisterIds.Contains(p.PolicyID));
Also better store policyRegisterIds as a HashSet<T> instead of a list for search in O(1) instead of O(n) of List<T>:
var policyRegisterIds = new HashSet<IdType>(db.PolicyRegisters......);
But better still is to remove the ToList() and let it all happen as one query in database:
var policyRegisterIds = db.PolicyRegisters.Where(pr => pr.StaffNumber == staffNumber &&
(pr.IsPolicyAccepted == false || pr.IsPolicyAccepted == null));
var policies = db.Policies.Where(p => policyRegisterIds.Any(pr => pr.PolicyID == p.PolicyID));
I try to change that query to QueryOver<> to be able to do the Distinct operation yet inside the (generated sql) query
var result = (from x in Session.Query<Events>()
join o in Session.Query<Receivers>() on x.ID equals o.ID
where x.Owner.ID == 1 //the user is the owner of that Event (not null)
||
x.EVType.ID == 123 //(not null)
||
x.Receivers.Count(y => y.User.ID == 1) > 0 //the user is one of the Event Receivers
select x.StartDate)
.Distinct();
I tried something like that
Events x = null;
List<Receivers> t = null;
var result = Session.QueryOver<Events>(() => x)
.JoinAlias(() => x.Receivers, () => t)
.Where(() => x.Owner.ID == 1
||
x.EVType.ID == 123
||
t.Count(y => y.User.ID == 1) > 0)
.TransformUsing(Transformers.DistinctRootEntity)
.Select(a => a.StartDate)
.List();
but then I got the Value can not be null. Parameter name: source exception. Any ideas how can I fix that query ?
edit
thanks to the xanatos' answer, the final SQL query is correct (I used his 2nd approach):
SELECT distinct this_.StartDate as y0_
FROM Events this_
WHERE
(
this_.UserID = ?
or
this_.EventTypeID = ?
or
exists (SELECT this_0_.ID as y0_
FROM Receivers this_0_
WHERE this_0_.UserID = ?)
)
"In QueryOver, aliases are assigned using an empty variable. The variable can be declared anywhere (but should be empty/default at runtime). The compiler can then check the syntax against the variable is used correctly, but at runtime the variable is not evaluated (it's just used as a placeholder for the alias)." http://nhibernate.info/blog/2009/12/17/queryover-in-nh-3-0.html
Setting List<Receivers> t to empty collection as you did (as you have mentioned in comments) means that you check is event id in local empty collection - doesn't have sense at all.
You can try do your query with subquery (should work but i'm not sure, I wrote it without testing, "by hand"):
Receivers receiversSubQueryAlias = null;
var subquery = session.QueryOver<Events>()
.JoinQueryOver<Receivers>(x => x.Receivers, () => receiversSubqueryAlias, JoinType.Inner)
.Where(()=> receiversSubQueryAlias.UserId == 1)
.Select(x => x.Id)
.TransformUsing(Transformers.DistinctRootEntity);
Events eventsAlias = null;
var mainQueryResults = session.QueryOver<Events>(() => eventsAilas)
.Where(Restrictions.Disjunction()
.Add(() => eventAlias.OwnerId == 1)
.Add(() => eventAlias.EVType.Id == 123)
.Add(Subqueries.WhereProperty<Events>(() => eventAlias.Id).In(subquery))
).Select(x => x.StartDate)
.TransformUsing(Transformers.DistinctRootEntity)
.List();
As written by #fex, you can't simply do a new List<Receivers>. The problem is that you can't mix QueryOver with "LINQ" (the t.Count(...) part). The QueryOver "parser" tries to execute "locally" the t.Count(...) instead of executing it in SQL.
As written by someone else, TransformUsing(Transformers.DistinctRootEntity) is client-side. If you want to do a DISTINCT server-side you have to use Projections.Distinct .
You have to make an explicit subquery. Here there are two variants of the query. the first one is more similar to the LINQ query, the second one doesn't use the Count but uses the Exist (in LINQ you could have done the same by changing the Count(...) > 0 with a Any(...)
Note that when you use a .Select() you normally have to explicitly tell the NHibernate the type of the .List<something>()
Events x = null;
Receivers t = null;
// Similar to LINQ, with COUNT
var subquery2 = QueryOver.Of<Receivers>(() => t)
.Where(() => t.SOMETHING == x.SOMETHING) // The JOIN clause between Receivers and Events
.ToRowCountQuery();
var result2 = Session.QueryOver<Events>(() => x)
.Where(Restrictions.Disjunction()
.Add(() => x.Owner.ID == 1)
.Add(() => x.EVType.ID == 123)
.Add(Subqueries.WhereValue(0).Lt(subquery2))
)
.Select(Projections.Distinct(Projections.Property(() => x.StartDate)))
.List<DateTime>();
// With EXIST
var subquery = QueryOver.Of<Receivers>(() => t)
.Where(() => t.SOMETHING == x.SOMETHING) // The JOIN clause between Receivers and Events
.Select(t1 => t1.ID);
var result = Session.QueryOver<Events>(() => x)
.Where(Restrictions.Disjunction()
.Add(() => x.Owner.ID == 1)
.Add(() => x.EVType.ID == 123)
.Add(Subqueries.WhereExists(subquery))
)
.Select(Projections.Distinct(Projections.Property(() => x.StartDate)))
.List<DateTime>();
Note that you'll have to set "manually" the JOIN condition in the subquery.
Hopefully this answer can help others. This error was being caused by declaring
List<Receivers> t = null;
followed by the query expression
t.Count(y => y.User.ID == 1) > 0
The QueryOver documentation states "The variable can be declared anywhere (but should be empty/default at runtime)." Since in this case, the place holder is a List, you must initialize it as an empty list.
List<Receivers> t = new List<Receivers>();
Otherwise, when you try to reference the Count method, or any other method on the placeholder object, the source (t) will be null.
This however still leaves a problem as #fex and #xanatos, in which it makes no sense to reference Count() from the alias List t, as it won't convert into SQL. Instead you should be creating a subquery. See their answers for more comprehensive answer.
I have the following Linq expression:
results = results.Where(r => r.FathersLast.StartsWith(fathersLast) && (mothersLast != string.Empty && r.MothersLast.StartsWith(mothersLast))).ToList();
What I want to do is:
If mothersLast variable is a string.empty, then don't consider filtering by r.MothersLast otherwise filter by r.MothersLast.StartWith(mothersLast).
Any clue on how to do that?
Thanks
Try the below :
results = results.Where(r => r.FathersLast.StartsWith(fathersLast) && (mothersLast == string.Empty || r.MothersLast.StartsWith(mothersLast))).ToList();
Well, every string starts with string.Empty, so if mothersLast == string.Empty you don't have to do any more work. Just simplify your query to:
results = results.Where(r => r.FathersLast.StartsWith(fathersLast) &&
r.MothersLast.StartsWith(mothersLast)).ToList();
Try the following
results = results
.Where(r =>
r.FathersLast.StartsWith(fathersLast) &&
(String.IsNullOrEmpty(mothersLast) || r.MothersLast.StartsWith(mothersLast)))
.ToList();
The operative change is the following
(String.IsNullOrEmpty(mothersLast) || r.MothersLast.StartsWith(mothersLast))
This will only check for the match of mothersLast is a string of length greater than 0
Why check the value of mothersLast for string.Empty repeatedly? I don't see anything that would modify it's value, so just check it once before running the LINQ statement:
if (mothersLast != string.Empty)
results = results.Where(r => r.FathersLast.StartsWith(fathersLast) &&
r.MothersLast.StartsWith(mothersLast)).ToList();
This is basically what you're code is doing, whether you intended it to or not.
It seems like you want to filter by fathersLast no matter what. In that case, for readability, just break it into two statements:
results = results.Where(r => r.FathersLast.StartsWith(fathersLast)).ToList();
if (mothersLast != string.Empty)
r.MothersLast.StartsWith(mothersLast)).ToList();
Casting to ToList() twice is unnecessary, and you could code around that, but I'll leave that up to you based on how big the list is.
results = results.Where(r => r.FathersLast.StartsWith(fathersLast) && (mothersLast == string.Empty || r.MothersLast.StartsWith(mothersLast))).ToList();