I have following code in a T-SQL query and I need to convert (rewrite) it into LINQ. Can somebody help me? Thanks
SELECT (select max(X.PocetDniPoPlatnosti)
from
(
select
(select top 1 datediff(day,datumplatnosti,getdate()) from planrealizace p
where p.cinnostsopidsop = cinnostsop.idsop and datumplatnosti <= getdate() and p.provest = 1 and p.datumprovedeni is null
order by p.datumplatnosti desc) as PocetDniPoPlatnosti
from cinnostsop
where cinnostSOP.LegislativneVyznamna = 1 and (CinnostSOP.ObjektId = 131476)) X) as PoPlatnosti
this should work, but I could not try it as I do not have any programming tools at home, so feel free to let me know if this doesn't work, and we can improve it together
var max = (from cp in cinnostsop.Where(c => c.LegislativneVyznamna = 1 && c.ObjektId = 131476)
join p in (
planrealizace.
Where(pz => pz.datumplatnosti <= DateTime.Now &&
pz.provest = 1 and pz.datumprovedeni is null).
GroupBy(pz => pz.cinnostsopidsop, pz => pz).
Select(g =>
new {
id = g.Key,
firstdate = (g.OrderByDescending(
pz => pz.datumplatnosti).
First().datumplatnosti - DateTime.Now
).Totaldays
})
) on cp.idsop equals p.id
select p.firstdate).Max(d => d);
Related
I have a SQL query which I want to convert to Linq.
This is my SQL query:
SELECT
Calisanlar.CalisanId,
CovidYakalanmaTarih,
CovidBitisTarih
FROM
Calisanlar
INNER JOIN
Covids ON Calisanlar.CalisanId = Covids.CalisanId
WHERE
Calisanlar.CalisanId IN (SELECT TOP 10 CalisanId
FROM Hastaliklar
GROUP BY CalisanId
ORDER BY COUNT(*) DESC)
AND DATEDIFF(DAY, CovidYakalanmaTarih, GETDATE()) BETWEEN 0 AND 30
I wrote this C# code, but it doesn't work as expected because i didn't write "DATEDIFF(DAY, CovidYakalanmaTarih, GETDATE()) BETWEEN 0 AND 30" linq version:
var query = context.Hastaliklar
.GroupBy(x => x.CalisanId)
.OrderByDescending(grp => grp.Count())
.Select(grp => grp.Key)
.Take(10)
.ToList();
var result = from hastalik in context.Hastaliklar
join covid in context.Covids
on hastalik.CalisanId equals covid.CalisanId
where query.Contains(hastalik.CalisanId)
&& EF.Functions.DateDiffDay(covid.CovidYakalanmaTarih, covid.CovidBitisTarih)
select new SonBirAyCovidDto
{
CalisanId = covid.CalisanId,
CovidYakalanmaTarih = covid.CovidYakalanmaTarih,
CovidBitisTarih = covid.CovidBitisTarih
};
There is not direct translation to BETWEEN in EF Core, but you can make other condition. Also it is better to remove ToList() from first query, in this case you will have only one roundtrip to database.
var query = context.Hastaliklar
.GroupBy(x => x.CalisanId)
.OrderByDescending(grp => grp.Count())
.Select(grp => grp.Key)
.Take(10);
var result =
from hastalik in context.Hastaliklar
join covid in context.Covids
on hastalik.CalisanId equals covid.CalisanId
where query.Contains(hastalik.CalisanId)
&& covid.CovidYakalanmaTarih <= covid.CovidBitisTarih
&& EF.Functions.DateDiffDay(covid.CovidYakalanmaTarih, covid.CovidBitisTarih) <= 30
select new SonBirAyCovidDto
{
CalisanId = covid.CalisanId,
CovidYakalanmaTarih = covid.CovidYakalanmaTarih,
CovidBitisTarih = covid.CovidBitisTarih
};
T-SQL query:
SELECT T1.ID,
T1.UserId,
T1.ServerId,
T1.DiskId,
T1.Date_ PreviousDate_,
T1.Row,
MIN(T2.Date_) AS Date_,
DATEDIFF(MINUTE, T1.Date_, MIN(T2.Date_)) AS MinutesDiff
FROM IesLogs T1
LEFT JOIN IesLogs T2
ON T1.DiskId = T2.DiskId
where T1.DiskId = 2 AND T2.Date_ > T1.Date_ AND T1.Row = T2.Row
GROUP BY T1.ID,T1.UserId, T1.ServerId, T1.DiskId, T1.Date_, T1.[Row]
ORDER BY T1.DiskId, T1.[Row], T1.Id
I am getting more data than I expected.
var result = (
from i in context.IesLogs
join i2 in context.IesLogs
on i.DiskId equals diskId into i2left
from i3 in i2left.DefaultIfEmpty()
where
i.UserId == userId
&& i3.Date > i.Date
&& i.Row == i3.Row
group i3 by new {i.Id, i.ServerId,i.DiskId, i.Row, PreviousDate = i.Date, i3.Date} into logs
orderby logs.Key.DiskId, logs.Key.Row,logs.Key.Id ascending
select new IesLogStatisticsDto
{
Id = logs.Key.Id,
ServerId = logs.Key.ServerId,
DiskId = logs.Key.DiskId,
PreviousDate = logs.Key.PreviousDate,
Date = logs.Min(x => x.Date),
Row = logs.Key.Row,
DateDiff = Convert.ToInt32((logs.Min(x => x.Date) - logs.Key.PreviousDate).TotalMinutes)
}).ToList();
I'm getting 12 when I should be getting 6 data. How Can I solve this ?
I think the reason why I'm getting a lot of data is the(i3.Date > i.Date) in the code blog above but I have to implement this line.
Your LINQ query has wrong grouping. You have to remove i3.Date from grouping key.
A little bit refactored:
var query =
from i in context.IesLogs
join i2 in context.IesLogs
on i.DiskId equals diskId into i2left
from i2 in i2left.DefaultIfEmpty()
where
i.UserId == userId
&& i2.Date > i.Date
&& i.Row == i2.Row
group i2 by new {i.Id, i.ServerId, i.DiskId, i.Row, PreviousDate = i.Date} into logs
orderby logs.Key.DiskId, logs.Key.Row, logs.Key.Id ascending
select new IesLogStatisticsDto
{
Id = logs.Key.Id,
ServerId = logs.Key.ServerId,
DiskId = logs.Key.DiskId,
PreviousDate = logs.Key.PreviousDate,
Date = logs.Min(x => x.Date),
Row = logs.Key.Row,
DateDiff = Convert.ToInt32((logs.Min(x => x.Date) - logs.Key.PreviousDate).TotalMinutes)
};
There was slowness in my .net core webapi application, I reviewed and redesigned my queries to resolve this issue. The code snippet below was written to bring in sales, payments for sales, and sales territories.
I first include the condition query and then the sub-entities in the query. Then I choose which columns to work with ".Select()".
Then I want to combine this table with the name information in other tables. For example, information such as Customer Name, Product Name is in the other table.
The first block of code I share below is a slow running linq query.
result.Results =
(from s in context.Sales
join sa in context.SaleProductServiceAreas on s.SaleId equals sa.SaleId
join sp in context.SalePayments on s.SaleId equals sp.SaleId into spleft
from sp in spleft.DefaultIfEmpty()
join c in context.Customers on s.CustomerId equals c.CustomerId
join p in context.ProductServices on s.ProductServiceId equals p.ProductServiceId
where s.Date >= firstDayOfMonth && s.Date <= lastDayOfMonth
group s by
new
{
s.SaleId,
s.CustomerId,
CustomerNameSurname = c.Name + ' ' + c.Surname,
ProductServiceName = p.Name,
s.Date,
s.Total,
s.Session,
p.ProductServiceId
} into grp
select new SaleJoinDto()
{
SaleId = grp.Key.SaleId,
CustomerNameSurname = grp.Key.CustomerNameSurname,
ProductServiceName = grp.Key.ProductServiceName,
Total = grp.Key.Total,
Date = grp.Key.Date,
Session = grp.Key.Session,
CustomerId = grp.Key.CustomerId,
ProductServiceId = grp.Key.ProductServiceId,
SaleProductServiceAreas = (from sps in context.SaleProductServiceAreas
join spa in context.ProductServiceAreas on sps.ProductServiceAreaId equals spa.ProductServiceAreaId
where sps.SaleId == grp.Key.SaleId
select new SaleProductServiceAreaJoinDto()
{
SaleProductServiceAreaId = sps.SaleProductServiceAreaId,
ProductServiceAreaName = spa.Name,
ProductServiceAreaId = sps.ProductServiceAreaId,
SaleId = sps.SaleId
}).ToList(),
SalePayments = (from spp in context.SalePayments
where spp.SaleId == grp.Key.SaleId
select new SalePaymentDto()
{
SaleId = spp.SaleId,
SalePaymentId = spp.SalePaymentId,
Total = spp.Total,
PaymentMethod = spp.PaymentMethod,
Date = spp.Date
}).ToList()
}).ToList();
["NEW"] This query I wrote is the query I rewrite as a result of the articles I have shared below.
Document of Microsoft Link for query
using (var context = new AppDbContext())
{
var result = new PagedResult<SaleJoinDto>();
result.CurrentPage = pageNumber;
result.PageSize = pageSize;
var pageCount = (double)result.RowCount / pageSize;
result.PageCount = (int)Math.Ceiling(pageCount);
var skip = (pageNumber - 1) * pageSize;
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
result.Results = await context.Sales
.Where(x => x.Date >= firstDayOfMonth && x.Date <= lastDayOfMonth)
.Include(x => x.SalePayments)
.Include(x => x.SaleProductServiceAreas)
.Select(s => new Sale()
{
SaleId = s.SaleId,
CustomerId = s.CustomerId,
Date = s.Date,
Total = s.Total,
Session = s.Session,
SalePayments = s.SalePayments,
SaleProductServiceAreas = s.SaleProductServiceAreas
})
.Join(context.Customers, sales => sales.CustomerId, customers => customers.CustomerId, (sales, customers) => new
{
sales,
customers
})
.Join(context.ProductServices, combinedSaleAndCus => combinedSaleAndCus.sales.ProductServiceId, product => product.ProductServiceId, (combinedSaleAndCus, product) => new SaleJoinDto()
{
SaleId = combinedSaleAndCus.sales.SaleId,
CustomerId = combinedSaleAndCus.sales.CustomerId,
Date = combinedSaleAndCus.sales.Date,
Total = combinedSaleAndCus.sales.Total,
Session = combinedSaleAndCus.sales.Session,
CustomerNameSurname = combinedSaleAndCus.customers.Name,
SalePayments = combinedSaleAndCus.sales.SalePayments.Select(x => new SalePaymentDto()
{
Date = x.Date,
PaymentMethod = x.PaymentMethod,
SaleId = x.SaleId,
SalePaymentId = x.SalePaymentId,
Total = x.Total
}).ToList(),
SaleProductServiceAreas = combinedSaleAndCus.sales.SaleProductServiceAreas.Join(context.ProductServiceAreas, sp => sp.ProductServiceAreaId, psa => psa.ProductServiceAreaId, (sp, psa) => new SaleProductServiceAreaJoinDto()
{
SaleProductServiceAreaId = sp.SaleProductServiceAreaId,
ProductServiceAreaName = psa.Name
}).ToList()
})
.ToListAsync();
result.RowCount = result.Results.Count();
result.Results = result.Results.OrderByDescending(x => x.Date).Skip(skip).Take(pageSize).ToList();
return result;
}
The problem is I do get the following error when I rewrite it according to this new query.
Where am I making a mistake in the query I just wrote?
{"The LINQ expression 'DbSet\r\n .Where(s => s.Date >=
__firstDayOfMonth_0 && s.Date <= __lastDayOfMonth_1)\r\n .Join(\r\n outer: DbSet, \r\n inner: s => s.CustomerId, \r\n
outerKeySelector: c => c.CustomerId, \r\n innerKeySelector: (s,
c) => new TransparentIdentifier<Sale, Customer>(\r\n Outer
= s, \r\n Inner = c\r\n ))\r\n .Join(\r\n outer: DbSet, \r\n inner: ti => new Sale{ \r\n
SaleId = ti.Outer.SaleId, \r\n CustomerId =
ti.Outer.CustomerId, \r\n Date = ti.Outer.Date, \r\n
Total = ti.Outer.Total, \r\n Session = ti.Outer.Session,
\r\n SalePayments = (MaterializeCollectionNavigation(\r\n
navigation: Navigation: Sale.SalePayments,\r\n
subquery: DbSet\r\n .Where(s0 =>
EF.Property(ti.Outer, "SaleId") != null &&
EF.Property(ti.Outer, "SaleId") == EF.Property(s0,
"SaleId"))), \r\n SaleProductServiceAreas =
(MaterializeCollectionNavigation(\r\n navigation:
Navigation: Sale.SaleProductServiceAreas,\r\n subquery:
DbSet\r\n .Where(s1 =>
EF.Property(ti.Outer, "SaleId") != null &&
EF.Property(ti.Outer, "SaleId") == EF.Property(s1,
"SaleId"))) \r\n }\r\n .ProductServiceId, \r\n
outerKeySelector: p => p.ProductServiceId, \r\n
innerKeySelector: (ti, p) => new
TransparentIdentifier<TransparentIdentifier<Sale, Customer>,
ProductService>(\r\n Outer = ti, \r\n Inner =
p\r\n ))'
could not be translated. Either rewrite the query in
a form that can be translated, or switch to client evaluation
explicitly by inserting a call to either AsEnumerable(),
AsAsyncEnumerable(), ToList(), or ToListAsync(). See
https://go.microsoft.com/fwlink/?linkid=2101038 for more
information."}
Removed not needed joins and grouping. It should be faster.
var query =
from s in context.Sales
join c in context.Customers on s.CustomerId equals c.CustomerId
join p in context.ProductServices on s.ProductServiceId equals p.ProductServiceId
where s.Date >= firstDayOfMonth && s.Date <= lastDayOfMonth
select new SaleJoinDto()
{
SaleId = s.SaleId,
CustomerNameSurname = c.Name + ' ' + c.Surname,
ProductServiceName = p.ProductServiceName,
Total = s.Total,
Date = s.Date,
Session = s.Session,
CustomerId = s.CustomerId,
ProductServiceId = p.ProductServiceId,
SaleProductServiceAreas = (from sps in context.SaleProductServiceAreas
join spa in context.ProductServiceAreas on sps.ProductServiceAreaId equals spa.ProductServiceAreaId
where sps.SaleId == s.SaleId
select new SaleProductServiceAreaJoinDto()
{
SaleProductServiceAreaId = sps.SaleProductServiceAreaId,
ProductServiceAreaName = spa.Name,
ProductServiceAreaId = sps.ProductServiceAreaId,
SaleId = sps.SaleId
}).ToList(),
SalePayments = (from spp in context.SalePayments
where spp.SaleId == s.SaleId
select new SalePaymentDto()
{
SaleId = spp.SaleId,
SalePaymentId = spp.SalePaymentId,
Total = spp.Total,
PaymentMethod = spp.PaymentMethod,
Date = spp.Date
}).ToList()
};
result.Results = query.ToList();
Anyway, even joins can be simplified if you have navigation properties which are not shown in original question.
I fixed the slow responsiveness of the app.
I was running the application on windows host. I changed my hosting to Centos 7 which is a linux distribution. Then when I run the application on Centos 7, the application accelerated perfectly and took flight.
My advice to all .net Core app developers, migrate your apps to linux. It is built to run on .net core linux distributions.
I share the problems I encountered while migrating the application to linux and how I solved it in the link below.
.Net Core 3.1 deploy on Centos 7
I have the following query that I would like to translate to linq.
SELECT
SUM(Credits.CreditAmount)
,Transactions.Id
,Person.FullName
,Person.Id
FROM
Person
JOIN
Transactions
ON Person.AccountId = Transactions.AccountId
JOIN Credits
ON Transactions.Id = Credits.TransactionId
WHERE
Person.Type = 'AccountHolder'
AND Person.Status = 'Active'
AND Transactions.CancelledDate IS NULL
AND Credits.CancelledDate IS NULL
GROUP BY Transactions.AccountId, Person.FullName, Person.Id
HAVING SUM(Credits.CreditAmount) > 20
This is what I came up with. It's an absolute pig... The SQL it generates must be awful.
var query = from p in Person
join t in Transactions
on p.AccountId equalas t.AccountId
join c in Credits
on t.TransactionId = c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
let sumC = grp.Select(x => x.CreditAmount).Sum()
select new
{
TotalCredit = sumC,
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
query.Where(p => p.TotalServiceCredit > 20);
The SQL query runs in approximately 3 seconds but I have yet to find the patience to let the Linq query finish. I was wondering if there is something different I should be doing to accomplish this "group, sum, having" query I'm trying to write? Is there something I can do to help Linq generate more performat SQL?
UPDATE
Turns out sgmoore had the right idea. The key to the performance issue was in his answer.
The difference between this
let sumC = grp.Select(x => x.CreditAmount).Sum()
and this
TotalCredit = grp.Sum(x => x.CreditAmount)
was the difference between a query that finishes and one that does not.
See my revised LINQ query below which completes in about the same time as the SQL (5.3 seconds for SQL vs 5.6 seconds for LINQ).
var query = from p in Person
join t in Transactions
on p.AccountId equalas t.AccountId
join c in Credits
on t.TransactionId = c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
select new
{
TotalCredit = grp.Sum(x => x.CreditAmount),
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
query.Where(p => p.TotalServiceCredit > 20);
Thanks for all your help!
I don't disagree with WEI_DBA's comment but if you need to do this, then you might find it easier to break this into several queries, eg
var query1 = from p in Person
join t in Transactions on p.AccountId equals t.AccountId
join c in Credits on t.TransactionId equals c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
select new { c.CreditAmount, t.AccountID, p.FullName, p.Id};
var query2 = (from p in query1
group p by new { p.AccountId, p.FullName, p.Id } into grp
select new
{
TotalCredit = grp.Sum(x => x.CreditAmount),
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
var query3 = (from p in query2 where p.TotalCredit > 20 select p);
Then you can let LINQ combine this into one sql command.
As always, it is a good idea to check and verify the actual TSQL generated.
I'm not good with LINQ yet and could use some help with the syntax.
Thanks!
The below query needs to be written in LINQ for C#.
SELECT Galleries.GalleryTitle, Media.*
FROM Galleries
INNER JOIN Media ON Galleries.GalleryID = Media.GalleryID
WHERE (Galleries.GalleryID = 150)
ORDER BY MediaDate DESC, MediaID DESC
Or with query syntax:
var query = from g in db.Galleries
join m in db.Media on g.GalleryID equals m.GalleryID
where g.GalleryID == 150
orderby m.MediaDate descending, m.MediaID descending
select new { g.GalleryTitle, Media = m };
Something like this:
var query = db.Galleries
.Join(db.Media, g => g.GalleryID, m => m.GalleryID, (g, m) => new {g, m})
.Where(r.g.GalleryID == 150)
.Select(res => new {res.g.GalleryTitle, Media = res.m}
.OrderByDescending(o => o.Media.MediaDate)
.ThenByDescending(o => o.Media.MediaID);