linq query, convert sql query to linq for VB.net - linq

I am trying to get fields from one table and max(expirationDate) from another table. This is my original linq query:
tanks = (From t In db.Table1 _
Where t.CompanyID = txtCompanyID.Text.Trim() _
Join d In db.Table2 On t.TankID Equals d.TankID
Order By d.ExpireDate Descending
Select t).ToList
that brings back multiple expireDates, I only want the max(expireDate) for each record
The following sql query works, I just need to put it into a linq query
select t1.*,
(Select MAX(Table2.ExpireDate)
from Table2 as t2
where t2.TankID = t1.TankID)
as max_expire_date
from Table1 as t1
where t1.CompanyID = '5467'
order by t1.CargoTankID
Does anybody know how to get this into linq? Thanks

tanks = db.Table1.Where( t => t.CompanyId == txtCompanyID.Text.Trim() )
.Join( db.Table2, t1 => t1.TankID, t2 => t2.TankID, (t1,t2) => new { Company = t1, t2.ExpireDate } )
.GroupBy( t => t.Company, (c,e) => new { Company = c Expiration = e.Max( x => x.ExpireDate ) } )
.ToList();
Best guess at VB
Dim tanks = db.Table1.Where( Function(t) t.CompanyId == txtCompanyID.Text.Trim() ) _
.Join( db.Table2, Function(t1) t1.TankID, Function(t2) t2.TankID, Function(t1,t2) New Thing With { .Company = t1, .ExpireDate = t2.ExpireDate } ) _
.GroupBy( Function(t) t.Company, Function(c,e) New Thing With { .Company = c, .Expiration = e.Max( Function(x) x.ExpireDate ) } ) _
.ToList()

Related

How to read data from a nested select query linq

I have a query like the following which is of type linq.
var querymiangin = (from t1 in _context.Apiapplicant
join t2 in _context.ApiApplicantHistory on t1.Id equals t2.ApiApplicantId
join t3 in _context.EntityType on t2.LastReqStatus equals t3.Id
where t1.IsDeleted == false && t1.LastRequestStatus == t2.Id && t3.Name == "granted"
select new { A = t1, B = t2, Year = t1.ApiRequestDate.Substring(0, 4), Month = t1.ApiRequestDate.Substring(5, 2) } into joined
group joined by new { joined.Year, joined.Month, joined.B.LastReqStatus } into grouped
select grouped.Select(g => new { ApiReqDate = g.A.ApiRequestDate, ApiDate = g.B.Date, ApiLastReqStatus = g.B.LastReqStatus, ApiYear = g.Year, ApiMonth = g.Month })).ToList();
In the select part, ApiReqDate and ApiDate has multiple records. Now my problem is for each group of month and year, I have multiple ApiDate and ApiReqDate records and I want for each group based on a condition (t1.LastRequestStatus == t2.Id && t3.Name == "granted") by using GetPersianDaysDiffDate() method, obtain the difference between ApiReqDate and its related ApiDate records for each month and then find their average in that month.
For doing that, I have written code like this:
var avgDateDiff = querymiangin.DefaultIfEmpty()
.GroupBy(x => new { x.ApiYear, x.ApiMonth }, (key, g) => new
{
key.ApiYear,
key.ApiYear,
Avg = g.Average(y => GetPersianDaysDiffDate(y.ApiReqDate,y.ApiDate))
})
.ToList();
But the problem is each parameter x.ApiYear, x.ApiMonth,y.ApiReqDate,y.ApiDate are unknown and it shows me error. I appreciate if anyone can suggest me a solution for that.
1 - For the first request querymiangin, you don't need to group by statement, change little the code to :
var querymiangin = (from t1 in Apiapplicant
join t2 in ApiApplicantHistory on t1.Id equals t2.ApiApplicantId
join t3 in EntityType on t2.LastReqStatus equals t3.Id
where t1.IsDeleted == false && t1.LastRequestStatus == t2.Id && t3.Name == "granted"
select new
{
ApiReqDate = t1.ApiRequestDate,
ApiDate = t2.Date,
ApiYear = t1.ApiRequestDate.Substring(0, 4),
ApiMonth = t1.ApiRequestDate.Substring(5, 2)
}).ToList();
2 - For the second query avgDateDiff, use GroupBy by ApiYear and ApiMonth and calculate the Average, like :
var avgDateDiff = querymiangin
.GroupBy(x => new { x.ApiYear, x.ApiMonth }, (key, g) => new
{
key.ApiYear,
key.ApiMonth,
Avg = g.Average(y => GetPersianDaysDiffDate(y.ApiReqDate, y.ApiDate))
}).ToList();
I hope you find this helpful.

How to convert this T-SQL query to LINQ syntax?

I´m trying to write below T-SQL query in LINQ. But I can´t figure out the syntax. Please help me out here.
SELECT
MONTH( O.Date) AS Month,
SUM( P.Price * PO.Quantity ) AS OrderSumPerMonth
FROM
Products P
INNER JOIN ProductOrders PO ON P.ProductId = PO.ProductId
INNER JOIN Orders O ON PO.OrderId = O.OrderId
GROUP BY
MONTH( O.Date );
var query = dbContext.ProductOrders
.GroupBy( po => new { po.Order.Date.Year, po.Order.Date.Month } )
.Select( grp => new
{
grp.Key,
OrderSumPerMonth = grp.Sum( po => po.Product.Price * po.Quantity )
} );
foreach(var row in query) {
WriteLine( "{0}/{1} - {2:C}", row.Key.Year, row.Key.Month, row.OrderSumPerMonth );
}

linq to entities left outer join

select SF.FOLDER_NAME,SF.CREATED_DATE,COUNT(st.FOLDER_ID)
from SURVEY_FOLDER SF with (nolock) left outer join SURVEY_TEMPLATE ST with (nolock)
on SF.FOLDER_ID=ST.FOLDER_ID
group by SF.FOLDER_NAME,SF.CREATED_DATE
I need this query in Linq :
I have tried this query,but unable to group by.
My Linq Query :
var data = (from xx in VDC.SURVEY_FOLDER
join yy in VDC.SURVEY_TEMPLATE
on xx.FOLDER_ID equals yy.FOLDER_ID into g
from grt in g.DefaultIfEmpty()
select
new
{
xx.FOLDER_NAME,
xx.CREATED_DATE,
count = g.Count()
}).ToList();
I got the Answer :
var data5 = (from SF in VDC.SURVEY_FOLDER
join ST in VDC.SURVEY_TEMPLATE on new { FOLDER_ID = SF.FOLDER_ID } equals new { FOLDER_ID = (Int64)ST.FOLDER_ID } into ST_join
from ST in ST_join.DefaultIfEmpty()
group new { SF, ST } by new
{
SF.FOLDER_NAME,
SF.CREATED_DATE
} into g
select new
{
g.Key.FOLDER_NAME,
CREATED_DATE = (DateTime?)g.Key.CREATED_DATE,
Column1 = (Int64?)g.Count(p => p.ST.FOLDER_ID != null)
}).ToList();

How to write this LINQ Query in a better way

I have one Linq Query. When I run the query, Only for 10 records its taking 13 seconds to extract the data to the model. I need to know the query which I wrote is good for performance or not. Please guide me what i am doing wrong.
Code
var stocktakelist = (from a in Db.Stocktakes
select new ExportStock
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = (from admin in Db.AdminAccounts where admin.Id == a.Id select admin.Name).FirstOrDefault(),
CreatedOn = a.CreatedOn,
Status = (from items in Db.Items where items.ItemNo == a.ItemNo select items.ItemStatu.Description).FirstOrDefault(),
Title = (from tit in Db.BibContents where tit.BibId == (from bibs in Db.Items where bibs.ItemNo == a.ItemNo select bibs.BibId).FirstOrDefault() && tit.TagNo == "245" && tit.Sfld == "a" select tit.Value).FirstOrDefault() // This line of Query only makes the performance Issue
}
).ToList();
Thanks
The reason this is so slow is because it is running the 3 inner LINQ statements for every item in the outer LINQ statement.
Using LINQ joins will run only 4 queries and then link them together, which is faster.
To find out how to join, there are plenty of resources on the Internet depending on the type of LINQ you are using.
If you're retrieving this data from a SQL server, perhaps consider doing this intensive work in SQL - this is what SQL was designed for and it's much quicker than .NET. EDIT: As highlighted below, the work is done in SQL if using LINQ to SQL/Entities and using the correct join syntax.
I was trying to create the corresponding query with some joins for practice.
I cannot test it and i'm not 100% sure that this query will you get the result
you are hoping for but maybe at least it will give you a hint on how to write
joins with linq.
from a in Db.Stocktakes
join admin in Db.AdminAccounts
on a.Id equals admin.Id
into adminJoinData
from adminJoinRecord in adminJoinData.DefaultIfEmpty( )
join items in Db.Items
on a.ItemNo equals items.ItemNo
into itemsJoinData
from itemsJoinRecord in itemsJoinData.DefaultIfEmpty( )
join title in Db.BibContents
(
from subQuery in Db.BibContents
where subQuery.TagNo == "245"
where subQuery.Sfld == "a"
select subquery
)
on title.BibId equals itemsJoinRecord.BidId
into titleJoinData
from titleJoinRecord in titleJoinData.DefaultIfEmpty( )
select new ExportStock( )
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = adminJoinRecord.Name,
CreatedOn = a.CreatedOn,
Status = itemsJoinRecord.ImemStatu.Description,
Title = titleJoinRecord.Value
}
As others have said, you should use Left Outer Joins in your LINQ just as you would if writing it in SQL.
Your query above will end up looking roughly like this once converted (this is untested, but gives the basic idea):
var a = from a in Db.Stocktakes
join admin in Db.AdminAccounts on admin.Id equals a.Id into tmpAdmin
from ad in tmpAdmin.DefaultIfEmpty()
join item in Db.Items on item.ItemNo equals a.ItemNo into tmpItem
from it in tmpItem.DefaultIfEmpty()
join title in Db.BibContents on bib.BibId equals items.BibId into tmpTitle
from ti in tmpTitle.DefaultIfEmpty()
where ti.TagNo == "245"
&& ti.Sfld == "a"
select new ExportStock
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = ad == null ? default(int?) : ad.Id,
CreatedOn = a.CreatedOn,
Status = it == null ? default(string) : it.ItemStatus.Description,
Title = ti == null ? default(string) : ti.Value
};
Using lambda expressions your query will look like this:
Db.Stocktakes
.Join(Db.AdminAccounts, a => a.Id, b => b.Id, (a,b) => new { a, AdminId = b.Name })
.Join(Db.Items, a => a.ItemNo, b => b.ItemNo, (a,b) => new { a, Status = b.ItemStatus.Description, BidId = b.BibId })
.Join(Db.BibContents, a => a.BibId, b => b.BibId, (a,b) => new { a, Value = b.Value, TagNo = b.TagNo, Sfld = b.Sfld })
.Where(a => a.TagNo == "245" && a.Sfld == "a")
.Select(a =>
new ExportStock { Id = a.Id,
ItemNo = a.ItemNo,
AdminId = a.AdminId,
CreatedOn = a.CreatedOn,
Status = a.Status,
Title = a.Value
}
).ToList();

Joining queries with Entity Framework

I have the table
MOVIES_RATING:
MovieID int
MovieRating decimal
I'd like to get 2 values using one query:
select COUNT(*)
FROM [dbo].[MOVIES_RATING]
where [dbo].[MOVIES_RATING].[MovieID] = 78
and
select SUM([dbo].[MOVIES_RATING].Rating)
FROM [dbo].[MOVIES_RATING]
where [dbo].[MOVIES_RATING].[MovieID] = 78
That's what I got in LINQ:
(from p in ef.MOVIES_RATING.Where(r => r.MovieID== movie_id)
let movieRates = ef.MOVIES_RATING.Where(r => r.MovieID == movie_id)
let count = movieRates.Count()
let averageUserRating = movieRates.Sum(c => c.MOVIES_RATING)/count
select new MovieRating {AverageUserRating = averageUserRating, VoteCount = count})
.Take(1);
Looks awful as well as SQL being generated:
SELECT
[Limit1].[MovieID] AS [MovieID],
[Limit1].[C2] AS [C1],
[Limit1].[C1] AS [C2]
FROM ( SELECT TOP 1
[GroupBy1].[A1] AS [C1],
[Extent1].[MovieID] AS [MovieID],
[GroupBy2].[A1] / CAST( [GroupBy1].[A1] AS decimal(19,0)) AS [C2]
FROM [dbo].[MOVIES_RATING] AS [Extent1]
CROSS JOIN (SELECT
COUNT(1) AS [A1]
FROM [dbo].[MOVIES_RATING] AS [Extent2]
WHERE [Extent2].[MovieID] = 78 ) AS [GroupBy1]
CROSS JOIN (SELECT
SUM([Extent3].[Rating]) AS [A1]
FROM [dbo].[MOVIES_RATING] AS [Extent3]
WHERE [Extent3].[MovieID] = 78 ) AS [GroupBy2]
WHERE [Extent1].[MovieID] = 78
) AS [Limit1]
I'm not sure it is best solution, so any help is appreciated.
I know It can be done using stored procedure, but if its could be done using LINQ it would be better.
from r in ef.MOVIES_RATING
group r by r.MovieID into g
where g.Key == movie_id
select new
{
Count = g.Count(),
Sum = g.Sum(r => r.Rating)
}
(or perhaps filter first then group; it probably translates to the same SQL anyway)
Another approach, using Aggregate:
ef.MOVIES_RATING
.Where(r => r.MovieID == movie_id)
.Aggregate(
new { Count = 0, Sum = 0 },
(acc, r) => new { Count = acc.Count + 1, Sum = acc.Sum + r.Rating });
(not sure how it translates to SQL though)
What about simple query:
var query = from m in context.Movies
where m.Id == 78
select new
{
Count = m.MovieRatings.Count(),
Sum = m.MovieRatings.Sum(mr => mr.Rating)
};
var data = query.SingleOrDefault();
Moving average computation to your application code should reduce the SQL query complexity.

Resources