in my DB, I have e.g. 13 orders.
The code below returns all of them, if the OrderID = 0 and CustomerName = "lorem".
If I comment the line (OrderID == 0) ?.... it works fine. What's wrong ?
var result = (from x in db.Order
where
(OrderID == 0) ? x.OrderID > 0 : x.OrderID == OrderID
&&
(string.IsNullOrEmpty(CustomerName)) ?
!string.IsNullOrEmpty(CustomerName)
:
x.User.Name.Contains(CustomerName)
select x)
.ToList();
I think you can not define conditional condition inside LINQ query in this way, what you can do is, for example:
var result = (from x in db.Order where
((OrderID == 0 && x.OrderID > 0) ||
(OrderID != 0 && x.OrderID == OrderID))
&&
(string.IsNullOrEmpty(CustomerName)) ?
!string.IsNullOrEmpty(CustomerName)
:
x.User.Name.Contains(CustomerName)....
Related
I have this query that is being partially evaluated locally and I am wondering how to prevent it.
It seems to be the conditional select that is causing the problem.
var fetchQuery = (
from udg in _entities.UberDirectGroups.AsNoTracking()
join uber in _entities.Ubers.AsNoTracking()
on udg.Id equals uber.Id
let memberCount = (
from t in _entities.UberDirects.AsNoTracking()
join u in _entities.Ubers.AsNoTracking()
on t.UberToId equals u.Id
where t.UberFromId == udg.Id && !u.Deleted
select u.UberTypeId == (byte)UberType.User ? 1 :
u.UberTypeId == (byte)UberType.Department ? u.Department.Users.Where(user => user.Deleted == false).Count() :
u.UberTypeId == (byte)UberType.Office ? u.tblOffice.tblDepartment.SelectMany(d => d.Users).Where(user => user.Deleted == false).Count() :
u.UberTypeId == (byte)UberType.ProjectGroup ? u.Group.GroupMembers.Select(pm => pm.User).Where(user => user.Deleted == false).Count() :
u.UberTypeId == (byte)UberType.Role ? _entities.Roles.Where(r => r.RoleDataId == u.tblRoleData.Id).Select(r => r.tblUser).Where(user => user.Deleted == false).Count() : 0
).Sum()
where
udg != null &&
uber != null &&
uber.InstanceId == instanceId &&
(!isSearch || udg.Name.Contains(searchText))
select new TargetGroupProjection
{
id = udg.Id,
name = udg.Name,
created = uber.Date,
toCount = memberCount
}
);
I hope you can help me to my code after I change the data type of the following I get this exception "Sequence contains no matching element exception. ". And I am sure this because of FirstOrDefault() Extension.
LandId - long
ShowMapPoint - string
Development - string
Location - string
MapPointX - string
MapPointY - string
AreaSize - from decimal? into long?
Premium - from decimal? into long?
TransactionPrice - from decimal? into long?
This is my code:
var result = _context.DwPropertyMasters.Where(x => x.ShowMapPoint == "Y")
.Select(x => new
{
x.LandId,
a = x.Development == null || x.Development == "" ? x.Location : x.Development,
x.MapPointX,
x.MapPointY,
AreaSize = x.AreaSize ?? 0,
Premium = x.Premium ?? 0,
b = (x.Premium == 0 ? null : x.Premium) * 100000000 / (x.AreaSize == 0 ? null : x.AreaSize) ?? 0,
c =
_context.DwPropertyDetails.Where(
z => (z.TransactionPrice > 0 || z.TransactionPrice != null) && z.LandId == x.LandId)
.GroupBy(z => z.LandId)
.Select(g =>
(g.Sum(p => p.TransactionPrice) == 0 ? null : g.Sum(p => p.TransactionPrice)) /
(g.Sum(p => p.ActualSize) == 0 ? null : g.Sum(p => p.ActualSize)) ?? 0)
.FirstOrDefault(),
d =
((x.AreaSize2 == 0 ? null : x.AreaSize2) == 0
? 0
: (x.Premium == 0 ? null : x.Premium) * 100000000 / (x.AreaSize2 == 0 ? null : x.AreaSize2)) ??
0,
x.LandType,
e =
_context.DwPropertyDetails.Where(
y => (y.TransactionPrice > 0 || y.TransactionPrice != null) && y.LandId == x.LandId)
.Select(y => new
{
a = 1
}).Count()
});
Your problem is in the sum of the Premium and TransactionPrice
If you grouping doesn't contain an item with a value, then it will try to sum null values. That can't work.
I would change it as follows:
(g.All(p => p.TransactionPrice == null) ? null : g.Where(p => p.TransactionPrice != null).Sum(p => p.TransactionPrice))
and
(g.All(p => p.ActualSize == null) ? null : g.Where(p => p.ActualSize != null).Sum(p => p.ActualSize)))
First check if everything is null, then it is null, else sum the values.
But you need to edit your code further, your current code would enable situations like 123 / null or null / 123. Which would also be a exception.
It is hard to understand what you are doing. It is way too complex with all these inline if's. And on line 13 you have:
z.TransactionPrice > 0 || z.TransactionPrice != null.
You might as well remove z.TransactionPrice > 0, because the second part allows all values (not null), including everything smaller than 0.
The 'Sequence contains no matching element' exception is typically something I'd expect when you use .First(). Not .FirstOrDefault().
Based on your code and what I think you want to achieve I have rewritten the query:
var result = _context.DwPropertyMasters.Where(x => x.ShowMapPoint == "Y")
.Select(x => new
{
x.LandId,
a = x.Development == null || x.Development == "" ? x.Location : x.Development,
x.MapPointX,
x.MapPointY,
AreaSize = x.AreaSize ?? 0,
Premium = x.Premium ?? 0,
b = (x.AreaSize == 0) ? 0 : (x.Premium * 100000000 / x.AreaSize ?? 0),
c = _context.DwPropertyDetails.Where(z => z.TransactionPrice > 0 && z.LandId == x.LandId)
.GroupBy(z => z.LandId)
.Select(g => g.Sum(p => p.ActualSize) == 0 ? 0 : (g.Sum(p => p.TransactionPrice) / g.Sum(p => p.ActualSize) ?? 0)
.FirstOrDefault(),
d = (x.AreaSize2 == 0) ? 0 : (x.Premium * 100000000 / x.AreaSize2 ?? 0),
x.LandType,
e = _context.DwPropertyDetails.Count(y => y.TransactionPrice > 0 && y.LandId == x.LandId)
});
I do not know if this works as you intended (and works at all since I didn't test this), but it is shorter and I hope more readable.
Keep in mind that this query is executed in sql server, so there is no need to check for null values. The only thing that must be prevented is to divide by zero. If we consider the next line:
b = (x.AreaSize == 0) ? 0 : (x.Premium * 100000000 / x.AreaSize ?? 0)
If:
x.AreaSize is null then (x.Premium * 100000000 / null ?? 0) => null ?? 0 => 0.
x.AreaSize = 0 then the result = 0.
x.Premium is null then the result is null / value ?? 0 => null ?? 0 => 0.
x.Premium = 0 then the result = 0.
I'm currently running the following query:
var results = from c in _context.Cs
join a in _context.Ca on c.Id equals a.CId
where c.Status == "A"
where c.CtId == ctId
where c.FY == fYear
where (a.PMId == lUserId || a.TLId == lInUserId)
select new { c.Id, c.T, c.C, c.S } into x
group x by new {x.Id, x.T, x.C, x.S} into g
orderby g.Key.T, g.Key.C, g.Key.S
select new { Id = g.Key.Id, T = g.Key.T, C = g.Key.C, S = g.Key.S}
Now I need to make the where (a.PMId == lUserId || a.TLId == lInUserId) line conditional on if lUserId != 0 (use it if not 0, ignore it if 0).
Normally, I would declare the variable results then set it in an if statement, but I have no idea how to define this data structure. It shows as being defined as:
IQueryble<'a>
'a is new { int Id, string T, string C, string S}
Whats the best way to accomplish this?
You can use || operator in the query so if first condition is true, the second will not be evaluated and if first is false that is not equal to 0 second will be evaluated:
where lUserId ==0 || (a.PMId == lUserId || a.TLId == lInUserId)
What I understand is:
use the condition a.PMId == lUserId || a.TLId == lInUserId if and only if UserId != 0
Ignore that condition if lUserId ==0
If I understand the requirement correctly, then && will be the operator that you have to use here. since it will skip checking the second condition if the first condition is false(that is UserId == 0).
I think you are looking for this:
where (UserId != 0 && a.PMId == lUserId || a.TLId == lInUserId)
My Filter is problematic. My goal is to have the datagrid on load show any with a created person where date > Today's day - 1 month.
I have some filters surname, forename. I want to Display any Person that had some activities within last 3 months. Thats found through this query
(ctx.Interactions.Where(z => z.Attendees.Where(w => w.Person_Id == x.Id).Any() && z.ActivityDate >= recent ).Any())
The issue I'm having is when surname or forename is filled, I want the query to ignore the created date prequisite and the Interaction Prerequisite.
Items.AddRange(ctx.People.
Where(x => (
((Surname.Length == 0) && (Forename.Length == 0)) ?
(x.Created > limit) : true &&
(((Surname.Length == 0) || x.Surname.StartsWith(Surname)) &&
((Forename.Length == 0) || x.Forename.StartsWith(Forename)) &&
(ctx.Interactions.Where(z => z.Attendees.Where(w => w.Person_Id == x.Id).Any() && z.ActivityDate >= recent ).Any())
One thing I did try was to move the Interaction query and had it with the x.created but that ruined the runtime. Currently it runs around 15seconds, with that change it takes about 2 mins. Any tips or suggestions would be great.
recent is today's date - 3 months
You can split the filtering expression:
var filteredPeople = ctx.People; // here var should be replaced with IEnumerable<T> where T is the type of items in People
if (string.IsNullOrEmpty(Surname) && string.IsNullOrEmpty(Forename))
filteredPeople = filteredPeople.Where(x => x.Created > limit);
else
{
if (!string.IsNullOrEmpty(Surname))
filteredPeople = filteredPeople.Where(x => x.Surname.StartsWith(Surname));
if (!string.IsNullOrEmpty(Forename))
filteredPeople = filteredPeople.Where(x => x.Forename.StartsWith(Forename));
filteredPeople = filteredPeople.Where(x => ctx.Interactions.Where(z => z.ActivityDate >= recent)
.Any(z => z.Attendees.Any(w => w.Person_id == p.Id)));
}
Items.AddRange(filteredPeople);
I think your issue may be in the use of your conditional operator. The conditional operator takes the ? and : clauses completely independently. So what you're currently telling it is,
If Surname and Forename are length 0
Then return ALL where x.Created > limit
Else
Then apply all other filters.
I've reworked the query a bit. This should improve performance because it will be retrieving fewer (and more accurate) results.
Items.AddRange(ctx.People.
Where(x => (
((Surname.Length == 0 && Forename.Length == 0) ? x.Created > limit : true)
&&
(
(Surname.Length == 0 || x.Surname.StartsWith(Surname))
&& (Forename.Length == 0 || x.Forename.StartsWith(Forename))
&& (ctx.Interactions.Any(z => z.Attendees.Any(w => w.Person_Id == x.Id) && z.ActivityDate >= recent))
)
Here's another version that doesn't hit the ctx twice, and instead traverses from Person > Attendee > Interaction instead of backwards. This might affect the performance as well:
Items.AddRange(ctx.People.
Where(x => (
((Surname.Length == 0 && Forename.Length == 0) ? x.Created > limit : true)
&&
(
(Surname.Length == 0 || x.Surname.StartsWith(Surname))
&& (Forename.Length == 0 || x.Forename.StartsWith(Forename))
&& x.Attendees.Any(attendee => attendee.Interactions.Any(interaction => interaction.ActivityDate >= recent))
)
I have repository with students and I want to get some students who have grades count in between 0 and 2.
This is my code:
_unitOfWork.Repository<Student>().Get(o => o.OrganizationId == organizationId
&& o.Grades.Where( o1 => o1.LastVersion
&& o1.Type == 5
&& o1.Value == 1).Count() > 0
&& o.Grades.Where( o1 => o1.LastVersion
&& o1.Type == 5
&& o1.Value == 1).Count() <= 2 );
This code is working, but my question is how to change this query with less code.
Is there any way to replace Count with some variable and not use it two times in query?
something like this?
var values = Enumerable.Range(1, 2);
_unitOfWork.Repository<Student>().Get(o => o.OrganizationId == organizationId
&& values.Contains(
o.Grades.Where( o1 => o1.LastVersion
&& o1.Type == 5
&& o1.Value == 1).Count()
));