Subtract two dates with 'let' variable then average()? - linq

Attempting to subtract two dates from one another to figure out the number of days, then execute .Average() on the 'let' variable avgConversion.
I encounter the following error; LINQ to Entities does not recognize the method 'System.TimeSpan Subtract(System.DateTime)' method, and this method cannot be translated into a store expression.
var averageConversion =
(
from r in db.Registrations
where
(bu == "All" || r.BusinessUnit.Equals(bu)) &&
(region == "All" || r.Region.Equals(region)) &&
(startDate == null || r.StartDate >= startDate) &&
(endDate == null || r.EndDate <= endDate) &&
!r.RegistrationStatus.Equals("Cancelled") &&
!r.Status.Equals("Cancelled")
let avgConversion = r.StartDate.Value.Subtract(r.RegistrationDate.Value).Days
select avgConversion
).Average();
Thanks to Enigma, this is what ended up solving the problem.
var dates = (from r in db.Registrations
where
(bu == "All" || r.BusinessUnit.Equals(bu)) &&
(region == "All" || r.Region.Equals(region)) &&
(startDate == null || r.StartDate >= startDate) &&
(endDate == null || r.EndDate <= endDate) &&
!r.RegistrationStatus.Equals("Cancelled") &&
!r.Status.Equals("Cancelled")
select new
{
r.RegistrationDate,
r.StartDate
}).ToList();
var avgConversion = (from d in dates
let AvgConversion = d.StartDate.Value.Subtract(d.RegistrationDate.Value).Days
select AvgConversion).Average();

Remember that Entity Framework translates a subset of all possible LINQ statements into SQL. If you use methods or functions that can't be translated the you get the "method cannot be translated into a store expression" error.
Instead you should pull your data into memory before doing the calculation so that you can run the full LINQ expression.
Like this:
var averageConversion =
(
from r in db.Registrations
where
(bu == "All" || r.BusinessUnit.Equals(bu)) &&
(region == "All" || r.Region.Equals(region)) &&
(startDate == null || r.StartDate >= startDate) &&
(endDate == null || r.EndDate <= endDate) &&
!r.RegistrationStatus.Equals("Cancelled") &&
!r.Status.Equals("Cancelled")
select new
{
r.StartDate,
r.RegistrationDate
}
)
.ToArray()
.Select(r => r.StartDate.Value.Subtract(r.RegistrationDate.Value).Days)
.Average();

Related

How do I negate this logical expression?

So, right now my code has something like this:
if(DateA <= utcNow || (DateA == null && DateB <= utcNow)) doSomething();
I want to do something like this now:
if(!InitialExpression) continue;
AFAIK, if A || B, the negation would be !A && !B.
But this doesn't work: if(DateA > utcNow && (DateA != null || DateB > utcNow)) continue;.
When DateA = null and DateB > utcNow it should fall into the continue but it doesn't.
Edit:
My mistake was assuming the opposite of DateA <= utcNow is DateA > utcNow. But it's DateA == null || DateA > utcNow
Option 1 - use an ELSE statement
if(DateA <= utcNow || (DateA == null && DateB <= utcNow))
{doSomething()
}else{
dpSomethingElse();
Option 2 - use ! in the operator
if(!(DateA <= utcNow || (DateA == null && DateB <= utcNow))) doSomethingElse();
Option 3 - negation - The condition of DataA not being null will need to go first. There is some context missing but assuming you want to negate the expression by ensuring that give preference to DateA if it is greater than utcNow, else check for DateB being greater then utcNow
if((DateA != null && DateA > utcNow) || DateB > utcNow) doSomethingElse()
The opposite of DateA <= utcNow || (DateA == null && DateB <= utcNow) is
(DateA == null || DateA > utcNow) && (DateA != null || DateB == null || DateB > utcNow)
Your logic was pretty much alright #Felipe. Just that you overlooked a tiny aspect.
The negation of <= is not just > but it also includes a NULL value.just add these 2 conditionals along with an OR operator. This should work.
Check the updated statement below:
(DateA == null || DateA > utcNow) && (DateA != null || DateB == null || DateB > utcNow)

Linq query where conditions not evaluating

Not all filtering in where contions. The first pass to check if items are active or discontinued evaluates then the second portion of the were evaluates to check what type of item. The last portion of the where checking for quantity values is not evaluating and with variables passed.
query:
from i in items
join idt in itemDetails on i.Id equals idt.ItemId
join ip in itemPrice on i.Id equals ip.ItemId
join s in supplier on i.SupplierID equals s.Id
join so in salesOrderItems on i.Id equals so.ItemId into salesTable
from x in salesTable.DefaultIfEmpty()
where (i.ItemStatus == "ACT" || i.ItemStatus == "DISC" && i.StoreID == null)
&& (i.ItemType == stock || i.ItemType == part || i.ItemType == specialOrder)
&& (idt.ReorderQty >= sales || idt.WarrantyQty >= warranty || idt.NextOrderQty >= next || idt.ReorderPoint > reorderPoint || x.SalesOrderItemStatus == requests)

Any vs Where clause in LINQ

I always thought LINQ to SQL equivalent for an exists query is to use Any(). But i recently wrote a query in LINQ , which basically is trying to find if duplicate records exists in single table.
Anycontext.Contacts.Any(c => ((c.FirstName == contact.FirstName && c.LastName == contact.LastName && c.AddressLine1 == contact.AddressLine1 && c.Zip == contact.Zip)||
(!String.IsNullOrEmpty(contact.Email) && c.Email == contact.Email)))
matching criteria is simple to find contacts with same FirstName, LastName and AddressLine1 or same Email. This query times out in 30 sec(default), there are just 500K rows in this table.
Wherecontext.Contacts.Where(c => ((c.FirstName == contact.FirstName && c.LastName == contact.LastName && c.AddressLine1 == contact.AddressLine1 && c.Zip == contact.Zip)||
(!String.IsNullOrEmpty(contact.Email) && c.Email == contact.Email))).Count()>0
I was forced to use Where clause and then do count greater than 0 to find if any duplicate exists in the set. What i can not understand is, why LINQ to SQL on simple Any clause timing out.
Any explanation will be really great here.
EDIT
SQL From from LINQ Pad
ANY
SELECT
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM [Accounts].[Contacts] AS [t0]
WHERE ([t0].[CompanyID] = #p0) AND ((([t0].[FirstName] = #p1) AND ([t0].[LastName] = #p2) AND ([t0].[AddressLine1] = #p3) AND ([t0].[Zip] = #p4)) OR (([t0].[FirstName] = #p5) AND ([t0].[LastName] = #p6) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM [Accounts].[PhoneNumbers] AS [t1]
WHERE ([t1].[ContactNumber] = #p7) AND ([t1].[ContactID] = [t0].[ContactID])
))))
) THEN 1
ELSE 0
END) AS [value]
Where
SELECT [t0].[ContactID]
,[t0].[CompanyID]
,[t0].[CompanyTitle]
,[t0].[FirstName]
,[t0].[LastName]
,[t0].[AddressLine1]
,[t0].[AddressLine2]
,[t0].[City]
,[t0].[State]
,[t0].[Zip]
,[t0].[Email]
,[t0].[Salutation]
,[t0].[IsActive]
FROM [Accounts].[Contacts] AS [t0]
WHERE ([t0].[CompanyID] = #p0)
AND (
(
([t0].[FirstName] = #p1)
AND ([t0].[LastName] = #p2)
AND ([t0].[AddressLine1] = #p3)
AND ([t0].[Zip] = #p4)
)
OR (
([t0].[FirstName] = #p5)
AND ([t0].[LastName] = #p6)
AND (
EXISTS (
SELECT NULL AS [EMPTY]
FROM [Accounts].[PhoneNumbers] AS [t1]
WHERE ([t1].[ContactNumber] = #p7)
AND ([t1].[ContactID] = [t0].[ContactID])
)
)
)
)
Not completely sure if this is what you want, but you could compare, I'm guessing you wont run the test often, as it would be better to test for existence before you input the data to the DB.
If you want to find the duplicates then
var queryA = from a in db.someTable
select a.value;
foreach(var row in queryA){
Console.Write(queryA.Where(b => b == row).Count() > 1 ? row: "");
}
If you just want to test if it exist then.
var queryA = from a in db.someTable
select a.value;
var queryB = queryA;
queryB.Distinct();
Console.Write(queryB.Count() != queryA.Count() ? "Yes" : "No");

How to write lambda (linq) expression for sql?

I have an Sql statement for which I need go generate corresponding Lambda Expression (Linq).
Here is the SQL
Declare #CurrentUserId as int
Declare #CurrentDate as datetime
Set #CurrentDate = GetDate()
Set #CurrentUserId = 1
Select C.conferenceId,C.specialtyId,C.name,C.city,S.abbr as statebbbr,CTRY.name as countryname,C.startdate,C.enddate
from Conferences C
Inner join (
Select distinct SpecialtyId
from UserContent
Where UserId = #CurrentUserId and DeletedFlag = 0
) DT on C.SpecialtyId = DT.SpecialtyId
Left outer join State S on C.StateId = S.StateId
Inner join Country CTRY on C.CountryId = CTRY.CountryId
Where C.DisplayStartDate <= #CurrentDate
and C.DisplayEndDate >= #CurrentDate
and C.DeletedFlag = 0
and C.Publish = 1
Order by C.startdate ASC
What wolud be the lambda(linq) expression for this?
Assume data context is in variable context
from c in context.conferences
join ctry in context.country on c.CountryId equals ctry.CountryId
join s1 in context.State on c.StateId equals s.StateId into s2
from s in s2.DefaultIfEmpty()
where
c.DisplayStartDate <= System.DateTime.Now
&& c.DisplayEndDate >= System.DateTime.Now
&& c.DeletedFlag == 0 // or false if represented as a bool
&& c.Publish == 1 // or true if represented as a bool
&& context.UserContent.Any(
x => x.SpecialityId == c.specialityId
&& x.UserId == currentUserId
&& x.DeletedFlag == 0
// or if represented as a bool "&& !x.DeletedFlag"
)
select new {
c.ConferenceId,
c.SpecialtyId,
c.name,
c.city,
stateabbr = s.abbr,
countryname = ctry.name,
c.startdate,
c.enddate
}

Sql to linq convention

i have a problem to build my linq query and i need you help , the following code is what i have got so far
, it does has some errors as expected, so, this is my sql query :
*im new to linq and did searched over google.
select CAST(h.changedate as date) as 'RegDate' ,count (cast(h.changedate as date)) as 'Amount' from T_TalmidStatusHistory h
join T_talmid t on h.talmidid = t.talmidid
where t.talmidStatusID=16 and h.[statusid] != 16
and h.id =
(
select max(id) from T_TalmidStatusHistory
where T_TalmidStatusHistory.talmidid=h.talmidid and T_TalmidStatusHistory.[statusid] != 16
)
group by CAST(h.changedate as date)
and this is what i have right now in linq:
var res = from r in db.T_TalmidStatusHistories
from m in db.T_TalmidStatusHistories
join t in db.T_Talmids on r.TalmidID equals t.TalmidID
where t.TalmidStatusID == 16 && r.StatusID != 16
&& r.id == from l in db.T_TalmidStatusHistories
where m.TalmidID == r.TalmidID && m.StatusID != 16
select new{db.T_TalmidStatusHistories.OrderByDescending(tp => tp.id).FirstOrDefault().id }
group h by h.changedate as date
select new { h.changedate as date, count (cast(h.changedate as date))};
Edit:
i'm expecting to get the number of students that sign up on each date,
my error is :
Operator '==' cannot be applied to operands of type 'int' and 'System.Linq.IQueryable'
at line : r.id == from l in db.T_TalmidStatusHistories
ty.
The whole part
from l in db.T_TalmidStatusHistories ... count (cast(h.changedate as date))}
is one query which is compared to r.id by the == operator.
Change it to
...
r.id == (db.T_TalmidStatusHistories
.Where(m.TalmidID == r.TalmidID && m.StatusID != 16)
.OrderByDescending(tp => tp.id).FirstOrDefault().id)
group h by h.changedate as date
select new { h.changedate as date, count (cast(h.changedate as date))};

Resources