Calculating Average Timespan between two dates in Entity Framework - entity-framework

I have a database table with two columns: StartDateTime and FinishDateTime. both are nullable datetime columns.
I'm wanting to calculate the Average time between both fields per row. ie the average duration of my recorded event.
I'm getting a "DbArithmeticExpression arguments must have a numeric common type."
Example EF code with a touch of simplification for the demo.
from p in new DbContext()
where p.user_id = 123
&& p.StartDateTime != null
&& p.FinishDateTime != null
select new {p.StartDateTime, p.FinishDateTime})
.Average(p=> (p.FinishDateTime.Value - p.StartDateTime.Value).Ticks)
I'd love an example of the above, as SQL makes this a breeze.

Its depends on your data provider, it may support DbFunctions and you could do something like this:
(from p in new DbContext()
where p.user_id = 123
&& p.StartDateTime != null
&& p.FinishDateTime != null
select new {p.StartDateTime, p.FinishDateTime})
.Average(x=> DbFunctions.DiffMilliseconds(p.FinishDateTime,p.StartDateTime))
if it doesn't, i think you have to go linq to objects after the select:
(from p in new DbContext()
where p.user_id = 123
&& p.StartDateTime != null
&& p.FinishDateTime != null
select new {p.StartDateTime, p.FinishDateTime})
.ToArray()
.Average(x=> (p.FinishDateTime -p.StartDateTime).Ticks)

Related

Linq to Entity Framework with Informix generates useless CAST

I have the following Linq query:
var asnPacApoRepository = repoFactory.GetRepository<asn_pac_apo>();
var query = asnPacApoRepository.Table
.Where(_ => positionList.Contains(_.pzn) && _.gueltig_von <= date &&
(date <= _.gueltig_bis || _.gueltig_bis == null));
This generates the SQL query:
SELECT *
FROM informix.asn_pac_apo AS Extent1
WHERE ((((CAST('06460518' AS nvarchar(8)) = Extent1.pzn) OR (CAST('10710808' AS nvarchar(8)) = Extent1.pzn)) OR ((CAST('00584142' AS nvarchar(8)) = Extent1.pzn) OR (CAST('03728156' AS nvarchar(8)) = Extent1.pzn))) AND (Extent1.gueltig_von <= '2016-04-24')) AND (('2016-04-24' <= Extent1.gueltig_bis) OR (Extent1.gueltig_bis IS NULL))
The issue with the generated query is performance, because the pzn column is of type:
and it is indexed, but the statement: CAST('06460518' AS nvarchar(8)) makes the index not to be used.
I was expecting Linq to generate the following query:
SELECT *
FROM informix.asn_pac_apo AS Extent1
WHERE (Extent1.pzn IN ('06460518','10710808','00584142','03728156') AND (Extent1.gueltig_von <= '2016-04-24')) AND (('2016-04-24' <= Extent1.gueltig_bis) OR (Extent1.gueltig_bis IS NULL));
If I create a linq query with Equals instead of Contains, the cast does not appear, and the SQL generated query is as expected.
How can I get rid of this useless CAST statement?
I set in .edmx the property Unicode=True:
but this doesn't seem to affect in any way the generated model, nor the generated query.
As a note, I use the old ObjectContext for my EF model and the database type is INFORMIX.

EF 6.0 Get by datetime

I want to read from the table by datetime. If I use this:
(from x in Db.Table where x.Date.Value == DateTime.Now select x).ToList();
my code throws EntityCommandExecutionException:
A failure occurred while giving parameter information to OLE DB
provider
So I use this:
(from x in Db.Table where DbFunctions.TruncateTime(x.Date) == DateTime.Now select x).ToList();
but it is very slowly (about 40 seconds). In my table is approximately 500 000 records.
Thanks for advice
define now property first and then query like following:
var now = DateTime.Now;
var list = Db.Table.Where(e=>e.Date == now).ToList();
Or:
(from x in Db.Table where x.Date == now select x).ToList();

why my Linqued query is not getting executed

I have this linqued query
var moreThen1dayLeavefed = (from LApp in db.LeaveApplications
join Emp in db.Employees
on LApp.Employee equals Convert.ToInt32(Emp.EmployeeNumber)
join LBrk in db.LeaveBreakups
on LApp.Id equals LBrk.LeaveApplication
where Emp.Team == 8 && LBrk.StartDate.Year == 2015 && LBrk.StartDate.Month == 5
select new { StartDate = LBrk.StartDate.Day, EndDate = LBrk.EndDate.Day, diff = (DbFunctions.DiffDays(LBrk.StartDate, LBrk.EndDate) + 1) }).ToList();
it gives error
LINQ to Entities does not recognize the method 'Int32 ToInt32(System.String)' method, and this method cannot be translated into a store expression.
on line 3, i.e
on LApp.Employee equals Convert.ToInt32(Emp.EmployeeNumber)
as I am converting the string to int during inner join
Just saw your related question. Your EmployeeNumber field seems to be filled with fixed size (5) zero left padded string representation of a number. If that's true, you can use the trick from how to sort varchar column containing numeric values with linq lambdas to Entity to solve the issue.
Just replace
on LApp.Employee equals Convert.ToInt32(Emp.EmployeeNumber)
with
on DbFunctions.Right("0000" + LApp.Employee.ToString(), 5) equals Emp.EmployeeNumber

How to translate SQL into Lambda for use in MS Entity Framework with Repository pattern usage

For example take these two tables:
Company
CompanyID | Name | Address | ...
Employee
EmployeeID | Name | Function | CompanyID | ...
where a Company has several Employees.
When we want to retrieve the Company and Employee data for a certain Employee, this simple SQL statement will do the job:
SELECT e.name as employeename, c.name as companyname
FROM Company c
INNER JOIN Employee e
ON c.CompanyID = e.CompanyID
where e.EmployeeID=3
Now, the question is how to translate this SQL statement into a 'lambda' construct. We have modelled the tables as objects in the MS Entity Framework where we also defined the relationship between the tables (.edmx file).
Also important to mention is that we use the 'Repository' pattern.
The closest I can get is something like this:
List<Company> tmp = _companyRepository.GetAll().Where
(
c.Employee.Any
(
e => e.FKEngineerID == engineerId && e.DbId == jobId
)
).ToList();
Any help is very much appreciated!
This should do, assuming your repositories are returning IQueryables of the types
var list = (from c in _companyRepository.GetAll()
join e in _employeeRepository.GetAll() on c.CompanyId equals e.CompanyId
where e.FKEngineerID == engineerId && e.DbId == jobId
select new
{
EmployeeName = e.name,
CompanyName = c.name
}).ToList();
Since you are constraining the query to a single employee (e.Employee=3) why don't you start with employees.
Also, your sql query return a custom set of columns, one column from the employee table and the other column from company table. To reflect that, you need a custom projection at the ef side.
var result = _employeeRepository.GetAll()
.Where( e => e.DbId == 3 ) // this corresponds to your e.EmployeeID = 3
.Select( e => new {
employeename = e.EmployeeName,
companyname = e.Company.CompanyName
} ) // this does the custom projection
.FirstOrDefault(); // since you want a single entry
if ( result != null ) {
// result is a value of anonymous type with
// two properties, employeename and companyname
}

Linq - Limit number of results by same value of a field

I have a problem with a creation of a Linq to Entities (Oracle 11g) request. Here is the
I have a table TREATMENT with three column (simplified version) : ID, STATE and APPLICATION. Here is a sample :
ID STATE APPLICATION
1 A MAJ
2 A FLUX
3 A FLUX
4 R REF
5 A REF
Now, my objectives are to retrieve the data with theses rules:
State must be A (added)
Number of rows per application below a max value
The max value is minored b the number of row with State = R (per application)
Exemple : If the max value is 1, I must retrieve row 1 and 2. (Can't retrieve row 5 since there is already a REF with state R (the row 4))
I manage to retrieve all the row when the number of R is equal or greater than the max value, but I don't see how to limit my number of result in order to respect the max value.
Here is the request :
using (Entities bdd = new Entities())
{
var treatments = from trt in bdd.TREATMENT
let app = from t in bdd.TREATMENT
where t.STATE == "R"
group t by t.APPLICATION into grouped
where grouped.Count() >= maxPerApplication
select grouped.Key
where trt.STATE == "A" && !app.Contains(trt.APPLICATION)
orderby trt.ID
select new TreatmentDto()
{
Id = trt.ID
};
result = treatments.ToList();
}
In SQL, I would use an inner request and a ROWNUM to limit the number of result, but I don't see how to do it. The only solution I see is to do the request in two parts, but I want to avoid this to maintain the consistency of the information.
I found a solution, not sure if it's the best, but it works :
using (Entities bdd = new Entities())
{
from trt in bdd.TREATMENT
where trt.STATE == "A" &&
(from trt2 in bdd.TREATMENT
where trt2.STATE == "A" && trt2.APPLICATION == trt.APPLICATION && trt2.ID <= trt.ID
select trt2).Count() <= maxPerApplication - (from appp in bdd.TREATMENT
where appp.STATE == "R"
&& appp.APPLICATION.Equals(trt.APPLICATION)
select appp).Count()
select new TreatmentDto()
{
Id = trt.ID
};
result = treatments.ToList();
}