Lambda expression for Entity Framework query - entity-framework

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
};

Related

Using Hibernate to get the latest row with a LocalDateTime

I have a Java8 application using SpringBoot, which is pulling in Hibernate core 5.3.10 (connected to PostgreSQL 11). A simplified explanation: the application is maintaining a history of changes to a series of bespoke UserData records, containing two LocalDateTime columns for startDate and endDate, and a userId column (plus other columns).
The semantics of the application are that a history of changes to the UserData are maintained by the start_date and end_date contain no duplicates (respectively), and that any row where the endDate is null is the currently active record for a user. (Accordingly, a user may have no currently active record.)
It is a simple matter to retrieve all of the active rows, and this is working well.
However, I have a requirement to retrieve the latest row for all users irrespective of whether the row is active or not.
One way to achieve this outcome using SQL is with a query something like the following:
select ud1.* from user_data ud1
where ud1.start_date = (select max(ud2.start_date) from user_data ud2
where ud2.user_id = ud1.user_id);
I have been attempting to write a CriteriaQuery to replicate the SQL, but I have run into a data type problem with the CriteriaBuilder.max method. The max method is complaining that it will only accept a type Number column. The code looks like this:
final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
final CriteriaQuery<UserDate> criteriaQuery = builder.createQuery(UserData.class);
final Root<UserData> ud1 = criteriaQuery.from(UserData.class);
final Subquery<LocalDateTime> maxUserDataStartDate = criteriaQuery.subquery(LocalDateTime.class);
final Root<UserData> ud2 = maxUserDataStartDate.from(UserData.class);
maxUserDataStartDate.select(builder.max(ud2.get("startDate"));
// ...
The problem is with the last line, where it complains that ud2.get("startDate") is not an extension of type Number - which is true, of course.
Does anybody know how to fix this situation? Especially, does anybody have an example they can share that does what I'm after?
You can do order by start_date desc and get top 1
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<UserData> criteriaQuery = builder.createQuery(UserData.class);
Root<UserData> ud = criteriaQuery.from(UserData.class);
criteriaQuery.orderBy(builder.desc(ud.get("startDate")));
entityManager.createQuery(criteriaQuery).getFirstResult();

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") });

How to write row_number() over clause in linq to Entity Framework

Using Entity Framework and LINQ, I need to get row number together with an entity, e.g. for loan I have multiple invoices and I want to select specific invoice together with its sequence number.
Basically, I'd need to know how to write equivalent to this:
select
nr, i.*
from
[Invoices] i
inner join
(select
row_number() over (order by IssueDate) nr, id
from
[Invoices]
where
LoanId = 5) t on t.id = i.id
where
i.id = 207
According to this post ROW_NUMBER is not supported in L2E. If you don't mind the overhead of loading all invoices for a given LoanId into memory, then it can be be done easily in C# with the overload of the Select method on IEnumerable that produces an index for each item, e.g.:
//First select the invoices
var invoices = from i in dbContext.Invoices
where i.LoanId == 5
order by i.IssueDate
select i;
var indexedInvoice = invoices.ToList().Select((i, count) => new { Invoice = i, RowCount = count })
.First(ii => ii.Invoice.Id == 207);
I can see how this can be less than optimal in some situations, so you might consider bypassing L2E here and execute your query as a plain old sql string, depending on how performance-critical it is, and on how many invoices there usually are for a single loan.

How to ORDER BY non-column field?

I am trying to create an Entity SQL that is a union of two sub-queries.
(SELECT VALUE DISTINCT ROW(e.ColumnA, e.ColumnB, 1 AS Rank) FROM Context.Entity AS E WHERE ...)
UNION ALL
(SELECT VALUE DISTINCT ROW(e.ColumnA, e.ColumnB, 2 AS Rank) FROM Context.Entity AS E WHERE ...)
ORDER BY *??* LIMIT 50
I have tried:
ORDER BY Rank
and
ORDER BY e.Rank
but I keep getting:
System.Data.EntitySqlException: The query syntax is not valid. Near keyword 'ORDER'
Edit:
This is Entity Framework. In C#, the query is executed using:
var esql = "...";
ObjectParameter parameter0 = new ObjectParameter("p0", value1);
ObjectParameter parameter1 = new ObjectParameter("p1", value2);
ObjectQuery<DbDataRecord> query = context.CreateQuery<DbDataRecord>(esql, parameter0, parameter1);
var queryResults = query.Execute(MergeOption.NoTracking);
There is only a small portion of my application where I have to resort to using Entity SQL. Generally, the main use case is when I need to do: "WHERE Column LIKE 'A % value % with % multiple % wildcards'".
I do not think it is a problem with the Rank column. I do think it is how I am trying to apply an order by to two different esql statements joined by union all. Could someone suggest:
How to apply a ORDER BY to this kind of UNION/UNION ALL statment
How to order by the non-entity column expression.
Thanks.

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/