How to convert Lambda Expression into SQL exp? - c#

I am having difficulty converting this expression to SQL expression. I tried various applications but I failed. I tried to convert it myself but the result is different.
db.Trans_SAPStat.Where(s => s.EmployeeID == EmployeeID && s.PaymentID != PaymentID && !s.Status.Equals("cancelled or", StringComparison.OrdinalIgnoreCase))
.Join(_db.Trans_PaymentDetail,
stat => stat.PaymentID,
paydet => paydet.PaymentID,
(stat, paydet) => new
{
InvoiceNo = paydet.Remarks,
paydet.Amount,
stat.Status,
paydet.PaymentCode
})
.Where(s => s.PaymentCode.ToLower() == "c")
.GroupBy(g => g.InvoiceNo)
.Select(lg =>
new
{
InvoiceNo = lg.Key,
TotalAmount = lg.Sum(w => w.Amount)
}).ToList();

If you have this code inside working application then try to use SQL profiler. Another option - linqpad

Try this:
SELECT
p.Remarks AS InvoiceNo,SUM(p.Amount) AS TotalAmount
FROM Trans_SAPStat AS s
INNER JOIN Trans_PaymentDetail AS p ON s.PaymentID = p.PaymentID
WHERE s.EmployeeID = #EmployeeID
AND s.PaymentID <> #PaymentID
AND LOWER(s.Status) <> 'cancelled or'
AND LOWER(s.PaymentCode) = 'c'
GROUP BY p.Remarks

You can try to set the query to a variable without materialization (.ToList()), then just use query.ToString(). This will return the actual SQL query.
var query = db.Trans_SAPStat.Where(....); // don't call .ToList()
var sqlQuery = query.ToString();
var result = query.ToList(); // materialization
NOTE: This is the default behaviour for entity framework / linq to entities IQueryable<T> interface.

Related

SQL Like clause in LINQ [duplicate]

This question already has answers here:
Like Operator in Entity Framework?
(9 answers)
Closed 1 year ago.
I am trying to migrate a SQL Server stored procedure to LINQ and I am having difficulties when I have a list of partial matches that I need to find in the main table.
In short I need to replicate the following SQL into a LINQ. Any help would be much appreciated.
SQL
DECLARE #filters TABLE([filter] NVARCHAR(20))
INSERT INTO #filters VALUES ('Den%');
INSERT INTO #filters VALUES ('%zil');
INSERT INTO #filters VALUES ('%la%');
SELECT c.*
FROM [Northwind].[dbo].[Customers] c
INNER JOIN #filters f ON c.Country LIKE (f.filter)
ORDER BY Country
C#
var filters = new string[] { "Den*", "*zil", "*la*" };
var results = from C in ctx.Customers
join f in filters c.Country like f
Select new
{
c.CustomerId,
c.Country
};
var result = context.Customers.AsNoTracking()
.Include(x => x.Country)
.Where(x => x.Country.Contains("la") || x.Country.Startwith("Den") || x.Country.EndWith("zil"))
You can use EF.Functions.Like() method provided in EF Core.
We use % for LIKE in strings and not *.
So your query would look like:
var filters = new string[] { "Den%", "%zil", "%la%" };
var result = context.Customers.AsNoTracking()
.Where(c => filters.Any(f => EF.Functions.Like(c.Country, f)))
.OrderBy(c => c.Country)
.ToList();
If you just have one filter then your query would simplify to:-
var filter = "%la%";
var result = context.Customers.AsNoTracking()
.Where(c => EF.Functions.Like(c.Country, filter))
.OrderBy(c => c.Country)
.ToList();
Yo could use the following example:
var result = context.Customers.AsNoTracking()
.Include(x => x.Country)
.Where(x => x.Country.Contains("Den"));
as this example:
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.contains?view=net-5.0

How to write linq query for this sql statement

How would you write a linq query with the following SQL statement. I've tried several methods referenced on stackoverflow but they either don't work with the EF version I'm using (EF core 3.5.1) or the DBMS (SQL Server).
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp = (select max(DateTimeStamp) from Products where a.ProductID = ProductID)
For reference, a couple that I've tried (both get run-time errors).
var results = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.OrderByDescending(x => x.DateTimeStamp).FirstOrDefault());
var results = _context.Products
.GroupBy(x => new { x.ProductID, x.DateTimeStamp })
.SelectMany(y => y.OrderByDescending(z => z.DateTimeStamp).Take(1))
Thanks!
I understand you would like to have a list of the latest prices of each products?
First of all I prefer to use group by option even over 1st query
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp IN (select max(DateTimeStamp) from Products group by ProductID)
Later Linq:
var maxDateTimeStamps = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.Max(x => x.DateTimeStamp)).ToArray();
var results = _context.Products.Where(s=>maxDateTimeStamps.Contains(s.DateTimeStamp));
-- all assuming that max datetime stamps are unique
I've managed to do it with the following which replicates the correlated sub query in the original post (other than using TOP and order by instead of the Max aggregate), though I feel like there must be a more elegant way to do this.
var results = from x
in _context.Products
where x.DateTimeStamp == (from y
in _context.Products
where y.ProductID == x.ProductID
orderby y.DateTimeStamp descending
select y.DateTimeStamp
).FirstOrDefault()
select x;
I prefer to break up these queries into IQueryable parts, do you can debug each "step".
Something like this:
IQueryable<ProductOrmEntity> pocoPerParentMaxUpdateDates =
entityDbContext.Products
//.Where(itm => itm.x == 1)/*if you need where */
.GroupBy(i => i.ProductID)
.Select(g => new ProductOrmEntity
{
ProductID = g.Key,
DateTimeStamp = g.Max(row => row.DateTimeStamp)
});
//// next line for debugging..do not leave in for production code
var temppocoPerParentMaxUpdateDates = pocoPerParentMaxUpdateDates.ToListAsync(CancellationToken.None);
IQueryable<ProductOrmEntity> filteredChildren =
from itm
in entityDbContext.Products
join pocoMaxUpdateDatePerParent in pocoPerParentMaxUpdateDates
on new { a = itm.DateTimeStamp, b = itm.ProductID }
equals
new { a = pocoMaxUpdateDatePerParent.DateTimeStamp, b = pocoMaxUpdateDatePerParent.ProductID }
// where
;
IEnumerable<ProductOrmEntity> hereIsWhatIWantItems = filteredChildren.ToListAsync(CancellationToken.None);
That last step, I am putting in an anonymous object. You can put the data in a "new ProductOrmEntity() { ProductID = pocoMaxUpdateDatePerParent.ProductID }...or you can get the FULL ProductOrmEntity object. Your original code, I don't know if getting all columns of the Product object is what you want, or only some of the columns of the object.

OUTER APPLY is not supported in this LINQ query

I need to run this query in a oracle 11.2 database, but the generated query contains a "OUTER APPLY". How can I solve it ?
var query = from r in Ctx.Reg
let status_1 = (r.Hist.OrderByDescending(o => o.Id).FirstOrDefault(h => h.RegId == r.Id).Status == 1)
let status_2 = (r.Hist.OrderByDescending(o => o.Id).Skip(1).FirstOrDefault(h => h.RegId == r.Id).Status == 2)
select new
{
r.Id,
...
status_1,
status_2
};
OUTER APPLY is generated by your let statement expressions. You can avoid it by turning them into EXISTS translatable expressions using the equivalent Any based LINQ constructs:
var query = from r in Ctx.Reg
let status_1 = r.Hist.OrderByDescending(h => h.Id).Take(1).Any(h => h.Status == 1)
let status_2 = r.Hist.OrderByDescending(h => h.Id).Skip(1).Take(1).Any(h => h.Status == 2)
select new
{
r.Id,
...
status_1,
status_2
};
Note that h.RegId == r.Id is not needed because that is implied by r.Hist navigation property.

Linq - Conversion error when simulating an exists expression

Im having a problem with Linq using Lambda Expressions. Im trying to do this select
SELECT L.IDLLAMADO FROM LLAMADOS L WHERE EXISTS (SELECT D.IDLLAMADO FROM DIAGNOSTICO D WHERE D.DESCRIPCION LIKE '%SOME VALUE%')
Some notes:
Im using IQueryable because Im appending joins and where depending on
the parameters of the method.
In the example I mapped only a property in my complex class because the rest are not useful in the example.
diagonostico is a string parameter.
My code is:
DbSet<Llamados> llamados = context.Set<Llamados>();
IQueryable<ComplexLlamadosAfil> query = llamados
.Select(e => new ComplexLlamadosAfil { IdLlamado = e.IdLlamado });
//If some conditions
query = query.Where(e => diagnosticos.Any(d => d.IdLlamado == e.IdLlamado &&
d.Descripcion.Contains(diagnostico)) == true);
There is not compilation error but when i run this i keep getting this error:
The object type
'System.Data.Objects.ObjectQuery`1[GAMP.MO.VW_DIAGNOSTICOS_LLAMADO]'
cannot be converted into
'System.Data.Entity.DbSet`1[GAMP.MO.VW_DIAGNOSTICOS_LLAMADO]'.
I also tried using .TakeWhile() instead of .Where() but no success.
Thanks for reading guys,
Pablo.
well, the message is rather clear, no ?
I would do
//Don't tell that it's a DbSet<Llamados>. You want an IQueryable<Llamados>
IQueryable<Llamados> llamados = context.Set<Llamados>().AsQueryable();
IQueryable<ComplexLlamadosAfil> query = llamados
.Select(e => new ComplexLlamadosAfil { IdLlamado = e.IdLlamado });
//If some conditions
query = query.Where(e => diagnosticos.Any(d => d.IdLlamado == e.IdLlamado &&
d.Descripcion.Contains(diagnostico)) == true);
or just use var
var llamados = context.Set<Llamados>().AsQueryable();
var query = llamados
.Select(e => new ComplexLlamadosAfil { IdLlamado = e.IdLlamado });
//If some conditions
query = query.Where(e => diagnosticos.Any(d => d.IdLlamado == e.IdLlamado &&
d.Descripcion.Contains(diagnostico)) == true);

Using Lambda to query collection / joined table

I have a lambda 'where' query, querying an Order table like this:
List<Order> returnedOrders = _session.Query<Script>()Where(s => s.orderId == orderIdParam).ToList();
I want to also check the value of a column in the related OrderDetails table. So returnedOrders has a collection of OrderDetails, i.e. returnedOrders.orderDetails
So the SQL query would look something like:
Where OrderId = 12345 and Order.OrderDetail.CreatedDate = '01-Jan-2013'
Can anyone help me with the correct syntax please?
You can use a logical AND (&&) inside the Where method:
var date = new Date(2013,1,1);
List<Order> returnedOrders =
_session.Query<Script>()
.Where(s =>
s.orderId == orderIdParam &&
s.OrderDetails.Any(d => d.CreatedDate == date))
.ToList();
You can alternatively append another Where method.
var date = new Date(2013,1,1);
List<Order> returnedOrders =
_session.Query<Script>()
.Where(s => s.orderId == orderIdParam)
.Where(s => s.OrderDetails.Any(d => d.CreatedDate == date))
.ToList();
Since you know Id of order it seems useless but something like this
from order in orders
from detail in order.Details
where
order.Id = orderId &&
order.Id == detail.OrderId &&
detail.CreateDate == createDate
select order

Categories