LINQ to Entities 4: Query with calculation in where clause - entity-framework

I have a table with a DateTime "TimeStamp" column and an int "TimeoutSeconds" column. I want to retrieve all records from this table where DateTime.Now - TimeStamp > TimeoutSeconds. In a stored proc this was a no brainer using GetDate():
select * from Schema.TableName mp
where (GetDate() - mp.[Timestamp]) > mp.Timeout
However, with Entity Framework using either LINQ syntax or Lambda I cannot do this because it seems the Lambda input variable (mp) cannot be used as part of a calculation only as part of a predicate, so this does not compile:
var records = context.TableName.Where(mp => (DateTime.Now - mp.TimeStamp) > mp.Timeout);
This does not compile.
I don't want to retrieve the whole table then do my filtering in memory and would rather not use a stored proc or Entity SQL. What are my options here?

This does not compile because you are comparing (DateTime.Now - mp.TimeStamp) which has return type System.TimeSpan to int. The first solution that comes to mind is to do
Where(mp => (DateTime.Now - mp.TimeStamp) > new TimeSpan(0, 0, 0, mp.Timeout))
Unfortunately this doesn't seem to work in EF, so if you have MS SQL Server as the DB, you can use SqlFunctions in EF4:
var records = context.
TableName.
Where(mp => System.Data.Objects.SqlClient.SqlFunctions.
DateDiff("s", mp.TimeStamp, DateTime.Now) > mp.Timeout);
http://msdn.microsoft.com/en-us/library/dd487052.aspx

Related

JPQL get difference in days between a column and now

I'm using hibernate and jpa in a spring boot application.
I have a hibernate entity with 2 columns, type (string) and date (LocalDate).
I want to select all the columns and the difference of days between my date column and now.
I succeeded in PostgreSQL: select date, date - current date from table;
I'm using an interface which extends JpaRepository. Until now i was successfully to insert new queries through #Query annotations.
I can't figure it out how to select my columns and a column containing the difference of days in jpql.
Kind regards,
Indeed you can use query creator. You have to create a new entity which has the same columns as the original table and in addition the calculated difference between the date column and now. You have to be careful which date type is your column.
In my experience only Date from java.util can be used for differences with CURRENT_DATE (i may be wrong).
public List<NewEntity> getTest() {
String queryStr = "select new com.entity.NewEntity(n.type, n.date - CURRENT_DATE as
time) from Table as n"
TypedQuery<PunteInspectieTimpRamas> query = entityManager.createQuery(queryStr,
NewEntity.class);
return query.getResults()
}
Not sure you can do this with jpql.
But you can use your query as a native query, directly in you repository:
#Query(value = "SELECT ... ", nativeQuery = true)
ClassToReturn methodName();
see https://www.baeldung.com/spring-data-jpa-query

How to format a number in Entity Framework LINQ (without trailing zeroes)?

In a SQL Server database I have a column of decimal datatype defined something like this:
CREATE TABLE MyTable
(
Id INT,
Number DECIMAL(9, 4)
)
I use Entity Framework and I would like to return column Number converted to a string with only the digits right of the decimal separator that are actually needed. A strict constraint is that a result must be an IQueryable.
So my query is:
IQueryable queryable = (
from myTable in MyDatabase.NyTable
select new
{
Id = myTable.Id,
Number = SqlFunctions.StringConvert(myTable.Number,9,4)
}
);
The problem with is that it always convert number to string with 4 decimals, even if they are 0.
Examples:
3 is converted to "3.0000"
1.2 is converted to "1.2000"
If I use other parameters for StringConvert i.e.
SqlFunctions.StringConvert(myTable.Number, 9, 2)
the results are also not OK:
0.375 gets rounded to 0.38.
StringConvert() function is translated into SQL Server function STR.
https://learn.microsoft.com/en-us/sql/t-sql/functions/str-transact-sql?view=sql-server-2017
This explains the weird results.
In the realm of Entity Framework and LINQ I was not able to find a working solution.
What I look for is something like C# function
String.Format("0.####", number)
but this cannot be used in a LINQ query.
In plain simple SQL I could write my query like this
SELECT
Id,
Number = CAST(CAST(Number AS REAL) AS VARCHAR(15))
FROM
MyTable
I have not managed to massage LINQ to produce query like that.
A workaround would be to forget doing this in LINQ, which is quite inflexible and messy thing, borderline on useless and just return type DECIMAL from database and do my formatting on a client side before displaying. But this is additional, unnecessary code and I would hate to di it that way if there perhaps is a simpler way via LINQ.
Is it possible to format numbers in LINQ queries?
I would absolutely return a decimal from he database and format it when needed. Possible directly after the query. But usually this is done at display time to take into account culture specific formatting from the the client.
var q =
(from myTable in MyDatabase.NyTable
select new
{
Id = myTable.Id,
Number = myTable.Number
})
.AsEnumerable()
.Select(x => new { Id = x.Id, Number = x.Number.ToString("G29") });

EntityFramework counting of query results vs counting list

Should efQuery.ToList().Count and efQuery.Count() produce the same value?
How is it possible that efQuery.ToList().Count and efQuery.Count() don't produce the same value?
//GetQuery() returns a default IDbSet which is used in EntityFramework
using (var ds = _provider.DataSource())
{
//return GetQuery(ds, filters).Count(); //returns 0???
return GetQuery(ds, filters).ToList().Count; //returns 605 which is correct based on filters
}
Just ran into this myself. In my case the issue is that the query has a .Select() clause that causes further relationships to be established which end up filtering the query further as the relationship inner join's constrain the result.
It appears that .Count() doesn't process the .Select() part of the query.
So I have:
// projection created
var ordersData = orders.Select( ord => new OrderData() {
OrderId = ord.OrderId,
... more simple 1 - 1 order maps
// Related values that cause relations in SQL
TotalItemsCost = ord.OrderLines.Sum(lin => lin.Qty*lin.Price),
CustomerName = ord.Customer.Name,
};
var count = ordersData.Count(); // 207
var count = ordersData.ToList().Count // 192
When I compare the SQL statements I find that Count() does a very simple SUM on the Orders table which returns all orders, while the second query is a monster of 100+ lines of SQL that has 10 inner joins that are triggered by the .Select() clause (there are a few more related values/aggregations retrieved than shown here).
Basically this seems to indicate that .Count() doesn't take the .Select() clause into account when it does its count, so those same relationships that cause further constraining of the result set are not fired for .Count().
I've been able to make this work by explicitly adding expressions to the .Count() method that pull in some of those aggregated result values which effectively force them into the .Count() query as well:
var count = ordersData.Count( o=> o.TotalItemsCost != -999 &&
o.Customer.Name != "!##"); // 207
The key is to make sure that any of the fields that are calculated or pull in related data and cause a relationship to fire, are included in the expression which forces Count() to include the required relationships in its query.
I realize this is a total hack and I'm hoping there's a better way, but for the moment this has allowed us at least to get the right value without pulling massive data down with .ToList() first.
Assuming here that efQuery is IQueryable:
ToList() actually executes a query. If changes to data in the datastore, between calls to ToList() and .Count(), result in a different resultset, calling ToList() will repopulate the list. ToList().Count and .Count() should then match until the data in the store changes the resultset again.

Fairly complex LINQ to Entities query

I have two entities, assume they are called Container and Record. They have a master-child relationship: a 'container' can hold many records.
The Records table in the database has the following columns:
Id
Date
Container_Id
RecordType_Id
The Record entity does not have any navigation properties that back reference the Container.
I am writing a LINQ query for my repository that will retrieve ONLY the records for a container that have the most recent date for each RecordType_Id. All older records should be ignored.
So if a container has say 5 records, one for each RecordType_Id, with the date 24/May/2011. But also has another 5 records for each RecordType_Id but with the date 20/May/2011. Then only the first 5 with the 24/May date will be retrieved and added to the collection in the container.
I came up with an SQL query that does what I need (but maybe there is some more efficient way?):
select t.*
from Records t
inner join (
select Container_Id, RecordType_Id, max(Date) AS MaxDate
from Records
group by Container_Id, RecordType_Id ) g
on t.Date = g.MaxDate
and t.Container_Id = g.Container_Id
and t.RecordType_Id = g.RecordType_Id
order by t.Container_Id
, t.RecordType_Id
, t.Date
However I am struggling to translate this into a proper LINQ query. EF is already generating a fairly large query all by itself just to load the entities, which makes me unsure of how much of this SQL query is actually relevant to the LINQ query.
Off the top of my head:
var q = from c in Container
from r in c.Records
group r by r.RecordType.RecordType_Id into g
select new
{
Container = c,
RecordType_Id = g.Key,
Records = from gr in g
let maxDate = g.Max(d => d.Date)
where gr.Date == maxDate
select gr
};
Try using LinqPad, it helps you test linq queries easily. Even against an existing EF model (which is in your project). Visit http://www.linqpad.net/

Lambda expression for Entity Framework query

I'm stuck trying to map this sql:
select dt.Id, dateadd(dd,datediff(dd,0,dt.CreatedAt),0) as Ct, DId, Amount
from dt, ad
where dt.ADId = ad.ADId and ad.Id = '13B29A01-8BF0-4EC9-80CA-089BA341E93D'
order by dateadd(dd,datediff(dd,0,dt.CreatedAt),0) desc, DId asc
Into an Entity Framework-compatible lambda query expression. I'd appreciate any help.
I think something like the code below should work.
Guid dtId = new Guid("13B29A01-8BF0-4EC9-80CA-089BA341E93D");
DateTime compareDt = new DateTime(...);
var q = from dt in dts
where dt.id == dtId
orderby dt.Ad.CreatedAt, Did
select new
{
dt.Ad,
(dt.CreatedAt - compareDt).Days,
DId,
Amount
};
dtId has to be outside of the query, because the entity framework mapper doesn't understand constructors that take parameters, similar for the DateTime. I couldn't completely figure out the datediff/dateadd part, looks like you're determining the total amount of days since a given datetime, which is what I assumed.
It could be that the datetime subtraction followed by TimeSpan.Days doesn't work in the query. If that's the case, pull it outside like so:
var q = from dt in dts
where dt.id == dtId
orderby dt.Ad.CreatedAt, Did
select new
{
dt.Ad,
dt.CreatedAt,
DId,
Amount
};
This creates an IEnumerable of objects that have a DateTime CreatedAt property. If you call .ToList() now, the query is executed, and you can calculate stuff that Entity Framework doesn't support. Again, if the first attempt worked, that's the best solution if the number of days since X is what you need.
from item in q.ToList()
select new
{
dt.Ad
(dt.CreatedAt - compareDt).Days,
DId,
Amount
};