Linq Query with Max Effective Date - linq

Having trouble understanding how i can convert the following SQL Query into LINQ. Specifically the MAX effective date parts.
SELECT A.NAME, X.XLATLONGNAME AS ACTION, C.DESCR, B.EFFDT
FROM ACTN_REASON_TBL C, XLATTABLE X, PERSONAL_DATA A, JOB B
WHERE A.EMPLID = B.EMPLID
AND B.ACTION = C.ACTION(+)
AND B.ACTION_REASON = C.ACTION_REASON(+)
AND (C.EFFDT = (SELECT MAX(C_ED.EFFDT) FROM ACTN_REASON_TBL C_ED
WHERE C.ACTION = C_ED.ACTION
AND C.ACTION_REASON = C_ED.ACTION_REASON
AND C_ED.EFFDT <= B.EFFDT)
OR C.EFFDT IS NULL)
AND X.FIELDNAME = 'ACTION'
AND B.ACTION = X.FIELDVALUE
AND X.EFFDT = (SELECT MAX(X_ED.EFFDT) FROM XLATTABLE X_ED
WHERE X.FIELDNAME = X_ED.FIELDNAME
AND X.LANGUAGE_CD = X_ED.LANGUAGE_CD
AND X.FIELDVALUE = X_ED.FIELDVALUE
AND X_ED.EFFDT <= SYSDATE)
AND B.ACTION_DT BETWEEN sysdate - 30 AND sysdate
AND B.ACTION NOT IN ('EOI','NBY','LIF','FSC','LOA','LTD','PLA','RFL','PAY')
ORDER BY A.NAME, B.EFFDT DESC
This is what i have so far for my LINQ query...
public ActionResult RecentTransaction()
{
RecentTransViewModel recTransModel = new RecentTransViewModel();
var minusThirty = DateTime.Today.AddDays(-90);
var today = DateTime.Now;
var exceptionList = new List<string> { "EOI", "NBY", "LIF", "FSC", "LOA", "LTD", "PLA", "RFL", "PAY" };
var transaction = (from p in recentTrans.PERSONAL_DATA
join j in recentTrans.JOB on p.EMPLID equals j.EMPLID
join a in recentTrans.ACTN_REASON_TBL on j.ACTION_REASON equals a.ACTION_REASON
join x in recentTrans.XLATTABLE_VW on j.ACTION equals x.FIELDVALUE
where x.FIELDNAME == "ACTION"
where j.ACTION_DT >= minusThirty
where j.ACTION_DT <= today
where !exceptionList.Contains(j.ACTION)
select new RecentTransViewModel
{
Name = p.NAME,
Action = x.XLATLONGNAME,
Descr = a.DESCR,
EffectiveDate = j.EFFDT
}).OrderBy(d => d.Name)
.ToList();
return View(transaction);
Any help is greatly appriciated!

LINQ allows you to add nested Queries within the same contex so that you can:
select new RecentTransViewModel
{
Name = p.NAME,
Action = x.XLATLONGNAME,
Descr = a.DESCR,
EffectiveDate = EffectiveDate = (from eft in recentTrans.XLATTABLE_VW
where eft.FIELDNAME == x.FIELDNAME AND eft.LANGUAGE_CD = X.LANGUAGE_CD AND
eft.FIELDVALUE = x.FIELDVALUE AND eft.EFFDT <= SYSDATE
select eft).Max(c=> c.EFFDT)
}).OrderBy(d => d.Name)
.ToList();

Related

C# linq query OUTER APPLY with SUM

Trying to convert a SQL Query to Linq:
SELECT GrossInvoiceAmount, C.SumOfPayments
FROM invoice
OUTER APPLY(
SELECT SUM(SumOfPayments) AS SumOfPayments FROM vw_sumOfPayments
WHERE vw_sumOfPayments.PaymentDate = '01/01/2010 00:00:00'
AND vw_sumOfPayments.InvoiceId = invoice.InvoiceId
) C
WHERE LastTransmitDate = '01/01/2010 00:00:00'
I have this in my C# code. It runs and gives results, but the invoice.GrossInvoiceAmount amount is wrong. Any ideas? Thanks.
var InvoiceQuery = (from invoice in this.Context.Invoices
join payment in this.Context.vw_sumOfPayments.Where(pay => DbFunctions.TruncateTime(pay.PaymentDate) >= startdate
&& DbFunctions.TruncateTime(pay.PaymentDate) <= enddate)
on invoice.InvoiceID equals payment.InvoiceID into pays
select new InvoiceModel{
InvoiceTypeId = invoice.InvoiceTypeId,
InvoiceNumber = invoice.InvoiceNumber,
InvoiceDate = invoice.InvoiceDate,
InvoiceAmount = invoice.GrossInvoiceAmount,
PaymentAmount = pays.AsEnumerable().Sum(o => o.SumOfPayments)
});

Using subquery in entity framework

I am trying to write the entity framework linq query to generate the following SQL. But I am not sure how to use subqueries with entity framework.
The Sql I want to generate is:
Declare #StartDate Datetime2; Set #Startdate = '2014-Feb-16 09:52'
Declare #EndDate Datetime2; Set #Enddate = '2014-Feb-18 09:52'
SELECT
[D].[RefId]
,[D].[StatusId]
,[D].[StatusDate]
,[D].[Reference]
,[RSC].[Event]
,[RSC].[Information]
,[RSC].[CreatedDate]
FROM (
SELECT
[R].[RefId]
,[R].[StatusId]
,[R].[StatusDate]
,[I].[Reference]
,(SELECT TOP 1
[RSC].[ChangeId]
FROM
[dbo].[StateChangeTable] AS [RSC] (nolock)
WHERE
[RSC].[RefId] = [R].[RefId]
ORDER BY
[RSC].[ChangeId] DESC) AS [LastChangeId]
FROM
[dbo].[Table1] AS [R] (nolock)
INNER JOIN
[dbo].[Table2] AS [I] (nolock)
ON
[R].[RefId] = [I].[RefId]
WHERE
[R].[StatusId] IN (4, 6)
AND [R].[StatusDate] between #StartDate and #EndDate
) AS [D]
INNER JOIN
[dbo].[StateChangeTable] AS [RSC] (nolock)
ON
[D].[LastChangeId] = [RSC].[ChangeId
]
And the code I wrote till now is:
return this.DbContext.Table1
.Join(this.DbContext.Table2, rc => rc.RefId, ri => ri.RefId, (rc, ri) => new { rc, ri })
.Join(this.DbContext.StateChangeTable, request => request.ri.RefId, rsc => rsc.RefId, (request, rsc) => new {request, rsc})
.Where(r => (r.rsc.ChangeId == ((from rsc in this.DbContext.StateChangeTable
orderby rsc.ChangeId descending
select rsc.ChangeId).FirstOrDefault())) &&
(r.request.rc.StatusId == 4 || r.request.rc.StatusId == 6) &&
(r.request.rc.StatusDate >= startDateTime && r.request.rc.StatusDate <= endDateTime))
.Select(requestDetails => new StatusDetail
{
RefId = requestDetails.request.rc.RefId,
StatusDate = requestDetails.request.rc.StatusDate,
StatusId = requestDetails.request.rc.StatusId,
Reference = requestDetails.request.ri.DistributionReference.Value,
Event = requestDetails.rsc.Event,
CreatedDate = requestDetails.rsc.CreatedDate,
Information = requestDetails.rsc.Information
}).ToList();
Can some please let me know what I am doing wrong?
Many Thanks
Here is the Full query
var query = (from D in
((from tab1 in DbContext.Table1
join tab2 in DbContext.Table2 on tab1.RefId equals tab2.RefId
where (tab1.StatusId == 4 || tab1.StatusId == 6)
&& (tab1.StatusDate >= startDate && tab1.StatusDate <= endDate)
select new
{
RefId = tab1.RefId,
StatusId = tab1.StatusId,
StatusDate = tab1.StatusDate,
Reference = tab2.Reference,
LastChangeId = (from RSC in DbContext.StateChangeTable
where RSC.RefId == tab1.RefId
orderby RSC.ChangeId descending
select RSC.ChangeId).FirstOrDefault()
}))
join RSC in DbContext.StateChangeTable on D.LastChangeId equals RSC.ChangeId
select new StatusDetail
{
RefId = D.RefId,
StatusId = D.StatusId,
StatusDate = D.StatusDate,
Reference = D.Reference,
Event = RSC.Event,
Information = RSC.Information,
CreatedDate = RSC.CreatedDate
}).ToList();
Don't use .Join() you have to use the navigation properties on your entities.

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();

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.

Filter a query by Date

I have the following query
var query =
from f in _db.Production
join g in _db.Run on f.show equals g.Production.show
select new ViewProductions {
Venuename = g.venue,
Showname = f.show,
StartDate = g.startDate,
EndDate = g.endDate
};
return View(query);
How would i add a where clause that would say
Where start date is in the next 3 months from today?
Thanks
Update
Working code
var now = DateTime.UtcNow;
var limit = now.AddDays(90);
var query =
from f in _db.Production
join g in _db.Run on f.show equals g.Production.show
where g.endDate >= now && g.startDate <= limit
select new ViewProductions
{
Venuename = g.venue,
Showname = f.show,
StartDate = g.startDate,
EndDate = g.endDate
};
return View(query);
Thanks again for all your help.
As you can't use any DateTime.Add* methods in linq-to-sql or entity framework, you'll have to use variables:
var now = DateTime.UtcNow;
var limit = now.AddDays(90);
var query = from f in _db.Production
join g in _db.Run on f.show equals g.Production.show
where g.StartDate >= now && g.StartDate <= limit
select new ViewProductions {
Venuename = g.venue,
Showname = f.show,
StartDate = g.startDate,
EndDate = g.endDate
};
Since this is Linq to Sql/Entities you will have to calculate the date first, then use it in the query:
DateTime futureDate = DateTime.Now.AddMonths(3);
from f in _db.Production
join g in _db.Run on f.show equals g.Production.show
where g.StartDate <= futureDate && g.StartDate >= DateTime.Now
...
Add this line yo your query:
var query =
from f in _db.Production
join g in _db.Run on f.show equals g.Production.show
where g.startDate > DateTime.Today &&
g.startDate < DateTime.Today.Add(TimeSpan.FromDays(90))
....

Resources