I have created a linq query to join tables and to do aggregate function and it takes more than a minute and it is affecting performance when executing the query in database it takes 18 seconds Kindly help me to improve the performance of Linq query.
Code:
List<int> oStatus = new List<int> { (int)STATUS.PAID, (int)STATUS.PARTIALY_PAID, (int)STATUS.OPEN, (int)STATUS.COMPLETED };
List<int> oLocationids = (
from loc in oTransactionContext.Location
join lum in oTransactionContext.LocationUserMap on loc.LocationId equals lum.LocationId
where lum.UserId == iUserID && loc.LocationName != "Local Purchase" && loc.LocationId !=0 &&loc.IsActive==true
select lum.LocationId
).ToList();
var oPT_Det = (
from inv in oTransactionContext.Invoice
join loc in oTransactionContext.Location on inv.LocationId equals loc.LocationId
where (inv.ClientId == (iClientID) && oLocationids.Contains(inv.LocationId.GetValueOrDefault()) &&
(inv.EndTime > DateTime.UtcNow.AddMonths(-6))
&& inv.IsActive == (true) && oStatus.Contains(inv.Status.GetValueOrDefault()))
group new { inv, loc } by new { inv.LocationId, loc.LocationName } into groupResult
select new OverAllSales
{
Location = Helper.CommonHelper.ParseString(groupResult.Key.LocationName),
InvoiceAmount = Helper.CommonHelper.ParseDecimal(groupResult.Sum(f => f.inv.TotalInvoiceAmount)),
}
).ToList();
Postgresql:
SELECT
COALESCE(SUM(inv.total_invoice_amount), 0) AS value1,
loc.location_name AS metric
FROM location loc
LEFT JOIN location_user_map LUM ON LUM.location_id = loc.location_id
LEFT OUTER JOIN invoice inv ON inv.client_id =2 AND inv.location_id = loc.location_id
AND inv.status IN (SELECT status_id FROM status WHERE status IN ('Paid', 'Partialy Paid', 'Open', 'Completed'))
WHERE loc.location_name NOT IN ('Local Purchase')
AND loc.location_id != 0
AND LUM.user_id IN ($user_ids)
AND inv.is_active = TRUE
AND CAST(inv.end_time AS date) > CURRENT_DATE - INTERVAL '2' MONTH
GROUP BY loc.location_name
ORDER BY value1 DESC
This is direct translation of the SQL. Should generate similar SQL query.
var startDate = DateTime.Date.AddMonths(-2);
int clientId = ...
int userId = ...
var oStatus = new List<int> { (int)STATUS.PAID, (int)STATUS.PARTIALY_PAID, (int)STATUS.OPEN, (int)STATUS.COMPLETED };
var query =
from loc in oTransactionContext.Location
join lum in oTransactionContext.LocationUserMap on loc.LocationId equals lum.LocationId
from inv in oTransactionContext.Invoice
.Where(inv => inv.ClientId == clientId && inv.LocationId = loc.LocationId
&& oStatus.Contains(inv.Status))
where
loc.LocationName != "Local Purchase"
&& loc.LocationId !=0
&& lum.UserId == userId
&& inv.IsActive == true
&& inv.end_time >= startDate
group inv by loc.LocationName into g
select new
{
Location = g.Key,
InvoiceAmount = g.Sum(x => x.total_invoice_amount) ?? 0
};
var oPT_Det = query.ToList();
Related
In my ASP.NET MVC application, I have created an HTML Table using the view model.
For this, I have written a query that shows only the data that ReOrderQty is !=0 and AvaQty is less than ReOrderQty.
List < RecognizedPartsViewModel > Reco = new List < RecognizedPartsViewModel > ();
var rData = (from i in db.InventoryMain
join p in db.PartCategory on i.PartCatogary equals p.Id
where i.ReOrderQty != 0 && i.AvaQty <= i.ReOrderQty && i.PartCatogary != 0
select new RecognizedPartsViewModel {
Id = i.Id,
PartNo = i.PartNo,
Description = i.PartDescription,
Model = i.PartModel,
AvaQty = i.AvaQty,
ReOrderQty = i.ReOrderQty,
PartCato = i.PartCatogary,
ABCD = i.A_B_C_D_Category
}).ToList();
So as so far, table data is showing according to the query.
There is another table where I store Orders according to the PartId. So I want to show that data on another column in the same HTML Table.
I can get those details by joining the join ord in db.OrderTable on i.Id equals ord.PartNo_Id
but when it does results only show the PartNumbers that only contains on the OrderTable only.
This is how I modified it as I mention.
List < RecognizedPartsViewModel > Reco = new List < RecognizedPartsViewModel > ();
var rData = (from i in db.InventoryMain
join p in db.PartCategory on i.PartCatogary equals p.Id
join ord in db.OrderTable on i.Id equals ord.PartNo_Id
where i.ReOrderQty != 0 && i.AvaQty <= i.ReOrderQty && i.PartCatogary != 0
select new RecognizedPartsViewModel {
Id = i.Id,
PartNo = i.PartNo,
Description = i.PartDescription,
Model = i.PartModel,
AvaQty = i.AvaQty,
ReOrderQty = i.ReOrderQty,
PartCato = i.PartCatogary,
ABCD = i.A_B_C_D_Category,
PastOrders = "Order Qty: " + ord.OrderQty
}).ToList();
So, when this does like I was said earlier not show every record, it shows only the record in the ordertable.
So how I can show those tables within the same view without losing my main requirement?
That would be
left outer join
var rData = (from i in db.InventoryMain
join p in db.PartCategory on i.PartCatogary equals p.Id
join ord in db.OrderTable on i.Id equals ord.PartNo_Id into leftjoin
from order in leftjoin.DefaultIfEmpty()
where i.ReOrderQty != 0 && i.AvaQty <= i.ReOrderQty && i.PartCatogary != 0
select new RecognizedPartsViewModel {
Id = i.Id,
PartNo = i.PartNo,
Description = i.PartDescription,
Model = i.PartModel,
AvaQty = i.AvaQty,
ReOrderQty = i.ReOrderQty,
PartCato = i.PartCatogary,
ABCD = i.A_B_C_D_Category,
PastOrders = "Order Qty: " + order?.OrderQty ?? string.Empty
}).ToList();
Reference: Perform left outer joins
What will be the proper linq syntax of below SQL Query ?
select a.id, a.AppointmentStatusID, ad.ID as DetailID
from [dbo].[Appointment] a, [dbo].[AppointmentDetail] ad
where a.[ID] = ad.[AppointmentID]
and a.CompanyID = 'a3dea87a-804e-4115-98cf-472988cf1678'
and a.LocationID = '3165caca-2a48-46f0-bbed-578cff29167t'
and ad.AppDateFrom <= {ts '2017-11-14 23:59:31'}
and ad.AppDateTo >= {ts '2017-11-14 00:00:00'}
and ad.[ApprovalStatusID] = 2
Problem I faced:
I required to filter Where Condition two times 1st at the time within the join & 2nd time during the object.Select expression, please check bellow
var results = (from a in appointments
join ad in _appointmentDetailRepository.GetAll() on a.ID equals ad.AppointmentID
where ad.ApprovalStatusID == 2
&& DbFunctions.TruncateTime(ad.AppDateFrom) <= DbFunctions.TruncateTime(viewmodel.AppointmentDate)
&& DbFunctions.TruncateTime(ad.AppDateTo) >= DbFunctions.TruncateTime(viewmodel.AppointmentDate)
orderby a.ID
select new Appointment
{
ID = a.ID,
CompanyID = a.CompanyID,
LocationID = a.LocationID,
AppointmentDetail = a.AppointmentDetail.Select(ad => new AppointmentDetail
{
ID = ad.ID,
AppDateFrom = ad.AppDateFrom,
AppDateTo = ad.AppDateTo,
AppointmentStatusID = ad.AppointmentStatusID,
}).Where(ad=> ad.ApprovalStatusID == 2
&& DbFunctions.TruncateTime(ad.AppDateFrom) <= DbFunctions.TruncateTime(viewmodel.AppointmentDate)
&& DbFunctions.TruncateTime(ad.AppDateTo) >= DbFunctions.TruncateTime(viewmodel.AppointmentDate)).ToList()
}).GroupBy(x => x.ID).Select(x => x.DefaultIfEmpty().FirstOrDefault());
Query : Why I required to write Where clause 2 times ?
Required Result
An Appointment Object --> Containing ICollection<AppoinmentDetails> if Details.Where Condition == True
From what I see (without knowing the model you have), it looks like you should use the already joined and filtered Details from ad instead of looking it up again from the Property a.AppointmentDetail...
Untested:
select new Appointment
{
ID = a.ID,
CompanyID = a.CompanyID,
LocationID = a.LocationID,
AppointmentDetail = ad.ToList(), // <-- don't you think?
...
}
For the given SQL query
select a.id, a.AppointmentStatusID, ad.ID as DetailID
from [dbo].[Appointment] a, [dbo].[AppointmentDetail] ad
where a.[ID] = ad.[AppointmentID]
and a.CompanyID = 'a3dea87a-804e-4115-98cf-472988cf1678'
and a.LocationID = '3165caca-2a48-46f0-bbed-578cff29167t'
and ad.AppDateFrom <= {ts '2017-11-14 23:59:31'}
and ad.AppDateTo >= {ts '2017-11-14 00:00:00'}
and ad.[ApprovalStatusID] = 2
LINQ query can be written as
var results = (from a in appointments
join ad in appointmentDetails on a.ID equals ad.AppointmentID
where ad.ApprovalStatusID == 2
&& a.CompanyID == "a3dea87a-804e-4115-98cf-472988cf1678"
&& a.LocationID == "3165caca-2a48-46f0-bbed-578cff29167t"
&& ad.AppDateFrom.Date <= viewmodel.AppointmentDate.Date
&& ad.AppDateTo.Date >= viewmodel.AppointmentDate.Date
select new
{
ID = a.ID,
AppointmentStatusID = a.AppointmentStatusID,
DetailID = ad.ID
}).ToList();
You can also write it like
var results = appointmentDetails
.Where(ad => ad.AppDateFrom.Date <= viewmodel.AppointmentDate.Date
&& ad.AppDateTo.Date >= viewmodel.AppointmentDate.Date
&& ad.ApprovalStatusID == 2
&& ad.Appointment.CompanyID == "a3dea87a-804e-4115-98cf-472988cf1678"
&& ad.Appointment.LocationID == "3165caca-2a48-46f0-bbed-578cff29167t")
.Select(ad =>
new
{
ID = ad.Appointment.ID,
AppointmentStatusID = ad.Appointment.AppointmentStatusID,
DetailID = ad.ID
})
.ToList()
As per the updated question, to get the the Appointment object with a collection of AppointmentDetails, please try this query
var results = appointmentDetails
.Where(ad => ad.AppDateFrom.Date <= viewmodel.AppointmentDate.Date
&& ad.AppDateTo.Date >= viewmodel.AppointmentDate.Date
&& ad.ApprovalStatusID == 2
&& ad.Appointment.CompanyID == "a3dea87a-804e-4115-98cf-472988cf1678"
&& ad.Appointment.LocationID == "3165caca-2a48-46f0-bbed-578cff29167t")
.Select(ad =>
new
{
ID = ad.Appointment.ID,
AppointmentStatusID = ad.Appointment.AppointmentStatusID,
Detail = ad
})
.AsEnumerable()
.GroupBy(a => new { a.ID, a.AppointmentStatusID })
.Select(a => new Appointment
{
ID = a.Key.ID,
AppointmentStatusID = a.Key.AppointmentStatusID,
AppointmentDetails = a.Select(d => d.Detail).ToList()
})
.ToList();
I have a LINQ query. But I need to get value of two columns from another subquery. This is my Linq query:
)from t in db.PUTAWAYs
join t0 in db.ASN_ITEM on t.AWB_NO equals t0.AWB_NO
join t1 in db.ASN_MASTER on t0.AWB_NO equals t1.AWB_NO
join t2 in db.ITEM_MASTER on t.ITEM_MASTER.ITEM_CODE equals t2.ITEM_CODE
join t3 in db.ASN_INPUT on t0.AWB_NO equals t3.AWB_NO
where
t3.ITEM == t2.ITEM_CODE &&
1 == 1 &&
(fromDate == "" || toDate == "" || (t0.REC_DATE.CompareTo(fromDate) >= 0 && t0.REC_DATE.CompareTo(toDate) <= 0)) &&
(AWB_NO == "" || (t0.AWB_NO == AWB_NO))
orderby
t.AWB_NO,
t0.REC_DATE,
t0.STYPE,
t2.PART_NO
select new ASNPutawayRep
{
AWB_NO = t.AWB_NO,
REC_DATE = t0.REC_DATE,
STYPE = t0.STYPE,
PART_NO = t2.PART_NO,
//LOCATION_AD = t.LOCATION_AD,
QNTY = t.QNTY,
//LOCATION_SD = t.LOCATION_SD,
REGION_ID = t.REGION_ID
}).Distinct();
Here in select portion of above query, instead of directly taking value of the column t.LOCATION_AD, I need to get it from SELECT LOC_NAME FROM LOCATION_MASTER WHERE LOC_CODE = t.LOCATION_AD
and instead of t.LOCATION_SD, I need to get value from SELECT LOC_NAME FROM LOCATION_MASTER where LOC_CODE = t.LOCATION_SD
How can I write this in LINQ. Is there any way to do this?
You can make use of let clause. It is useful to store the result of sub-expression in order to use it in subsequent clauses.
Example:
(from t in db.PUTAWAYs
...
let locAd = from l in LOCATION_MASTER where LOC_CODE = t.LOCATION_SD select l.LOC_NAME
where
...
orderby
...
select new ASNPutawayRep
{
LOCATION_AD = locAd,
}).Distinct();
Also, you can directly write LINQ without using let clause:
(from t in db.PUTAWAYs
...
where
...
orderby
...
select new ASNPutawayRep
{
LOCATION_AD = from l in LOCATION_MASTER where LOC_CODE = t.LOCATION_SD select l.LOC_NAME
}).Distinct();
You can use AsQueryable to achieve this
from t in db.PUTAWAYs
join t0 in db.ASN_ITEM on t.AWB_NO equals t0.AWB_NO
join t1 in db.ASN_MASTER on t0.AWB_NO equals t1.AWB_NO
join t2 in db.ITEM_MASTER on t.ITEM_MASTER.ITEM_CODE equals t2.ITEM_CODE
join t3 in db.ASN_INPUT on t0.AWB_NO equals t3.AWB_NO
where
t3.ITEM == t2.ITEM_CODE &&
1 == 1 &&
(fromDate == "" || toDate == "" || (t0.REC_DATE.CompareTo(fromDate) >= 0 && t0.REC_DATE.CompareTo(toDate) <= 0)) &&
(AWB_NO == "" || (t0.AWB_NO == AWB_NO))
orderby
t.AWB_NO,
t0.REC_DATE,
t0.STYPE,
t2.PART_NO
select new ASNPutawayRep
{
AWB_NO = t.AWB_NO,
REC_DATE = t0.REC_DATE,
STYPE = t0.STYPE,
PART_NO = t2.PART_NO,
LOCATION_AD = (from l in db.LOCATION_MASTER
where l.LOC_CODE = t.LOCATION_AD
select LocName)ToList().FirstorDefault(),
QNTY = t.QNTY,
LOCATION_SD = (from l in db.LOCATION_MASTER
where l.LOC_CODE = t.LOCATION_SD
select LocName).ToList().FirstorDefault(),
REGION_ID = t.REGION_ID
}).Distinct();
I got the famous "only primitive types or enumeration types..." error, and I cannot find the solution.
This is the code that is making my head explode (it's part of a select in another LINQ code):
Min = (from inddetails in EntitiesDB.ConfSet
where (final.Max(x => x.hosp.Hos_NumOnc) > inddetails.Conf_Desde && final.Max(x => x.hosp.Hos_NumOnc) < inddetails.Conf_Hasta)
|| final.Max(x => x.hosp.Hos_NumOnc) > (from inddetails2 in EntitiesDB.ConfSet select inddetails2.Conf_Hasta).Max()
select inddetails.Conf_NumeroRegistros)
Here is the full code as requested with the last updates (nothing changed):
var result = from indicadores in EntitiesDB.Catalogo_IndicadoresSet
join crit in EntitiesDB.Catalogo_CriteriosSet on indicadores.CodigoCriterio equals crit.CodigoCriterio
join dimen in EntitiesDB.Catalogo_DimensionSet on crit.CodigoDimension equals dimen.CodigoDimension
join grupo in EntitiesDB.Catalogo_GruposSet on dimen.CodigoGrupo equals grupo.CodigoGrupo
join indicador_resultado in EntitiesDB.Catalogo_Indicador_ResultadoSet.DefaultIfEmpty() on indicadores.CodigoIndicador equals indicador_resultado.CodigoIndicador /*into joined
from j in joined.DefaultIfEmpty()*/
join user in EntitiesDB.UsuariosSet on indicador_resultado.CodigoUsuario equals user.CodigoUsuario
join hosp in EntitiesDB.HospitalesSet on user.CodigoHospital equals hosp.CodigoHospital
join hosper in EntitiesDB.Rel_Hospital_PeriodoSet on hosp.CodigoHospital equals hosper.CodigoHospital
join period in EntitiesDB.PeriodosSet on hosper.CodigoPeriodo equals period.CodigoPeriodo
where period.CodigoPeriodo == periodos.CodigoPeriodo
group new { indicadores, hosper, hosp, grupo, crit, dimen, indicador_resultado, user, period } by new { hosper.CodigoPeriodo, hosp.CodigoHospital, grupo.CodigoGrupo, indicadores.CodigoIndicador, period.Per_Nombre, hosp.Hos_Nombre, hosp.Hos_NumeroOncologos, grupo.Gru_Descripcion, indicador_resultado.CodigoResultado, indicador_resultado.Resul_Completado, indicador_resultado.Resul_Numerador, indicador_resultado.Resul_Denominador, indicador_resultado.Resul_Valor, indicador_resultado.Resul_Objetivo, indicador_resultado.Resul_Variacion, indicador_resultado.Resul_Detalle, indicador_resultado.Resul_Fecha, indicadores.Ind_Descripcion, dimen.CodigoDimension, crit.CodigoCriterio } into final
orderby final.Key.CodigoPeriodo, final.Key.CodigoHospital, final.Key.CodigoGrupo
select new
{
CodigoPeriodo = final.Key.CodigoPeriodo,
NombrePeriodo = final.Key.Per_Nombre,
CodigoHospital = final.Key.CodigoHospital,
NombreHospital = final.Key.Hos_Nombre,
NumeroOncologos = final.Key.Hos_NumeroOncologos),
CodigoGrupo = final.Key.CodigoGrupo,
NombreGrupo = final.Key.Gru_Descripcion,
CodigoResultado = final.Max(x => x.indicador_resultado.CodigoResultado),
Completado = final.Key.Resul_Completado,
Numerador = final.Max(x => x.indicador_resultado.Resul_Numerador),
Denominador = final.Max(x => x.indicador_resultado.Resul_Denominador),
Valor = final.Max(x => x.indicador_resultado.Resul_Valor),
Objetivo = final.Max(x => x.indicador_resultado.Resul_Objetivo),
Variacion = final.Max(x => x.indicador_resultado.Resul_Variacion),
Detalle = final.Key.Resul_Detalle,
CodigoIndicador = final.Key.CodigoIndicador,
NombreIndicador = final.Key.Ind_Descripcion,
CodigoDimension = final.Max(x => x.dimen.CodigoDimension),
CodigoCriterio = final.Max(x => x.crit.CodigoCriterio),
CasosMinimos = (from inddetalle in EntitiesDB.Configuracion_IndicadoresDetalleSet
where (final.Key.Hos_NumeroOncologos > inddetalle.Conf_Desde && final.Key.Hos_NumeroOncologos < inddetalle.Conf_Hasta)
|| final.Key.Hos_NumeroOncologos) > valorMaximo
select inddetalle.Conf_NumeroRegistros)
};
Take the max value out of the query:
var finalMax = final.Max(x => x.hosp.Hos_NumOnc);
Min = (from inddetails in EntitiesDB.ConfSet
where (finalMax > inddetails.Conf_Desde
&& finalMax < inddetails.Conf_Hasta)
|| finalMax > (from inddetails2 in EntitiesDB.ConfSet select inddetails2.Conf_Hasta).Max()
select inddetails.Conf_NumeroRegistros);
final is a collection of (non-primitive) objects, for which there is no SQL equivalent. It's also more efficient to do it this way.
I have this MS-SQL statement :
SELECT cv.id FROM ContactValue cv
INNER JOIN (
SELECT mainId, max(version) as v
FROM ContactValue
WHERE version <= $Version(int)
GROUP BY mainId
)
AS t ON t.mainId = cv.mainId AND t.v = cv.version
WHERE cv.contact_id = $ContactID(int)
AND cv.isActive = 1
ORDER BY sort'
and would like to make it in linq.
I did make above query divided into multiple queries witch performence is not fast.
Does it exist any linq to linq joining
My C# code :
var groupMax = from cv in db.ContactValue
where cv.contact_id == ContactID && cv.version <= Version
orderby cv.sort
group cv by cv.mainId into gcv
select new { mainID = gcv.Key, version = gcv.Max(cv => cv.version) };
foreach (var data in groupMax.ToList())
{
var Query = from cv in db.ContactValue
where cv.contact_id == ContactID && cv.mainId == data.mainID && cv.version == data.version && cv.isActive == true
select cv;
if (Query.Count() > 0)
{
ContactValue tmp = Query.First();
}
}
I would love to get all contacts with 1-2 queries not 1 query then for each contact another query...
Please help me !
Yes, Linq to SQL does have an inner join implemented:
var groupMax =
from cv in db.ContactValue
where cv.contact_id == ContactID && cv.version <= Version
orderby cv.sort
group cv by cv.mainId into gcv
select new { mainID = gcv.Key, version = gcv.Max(cv => cv.version) };
var res =
from cv in db.ContactValue
join gm in groupMax on cv.version equals gm.version
where cv.contact_id == ContactID && cv.isActive
orderby cv.version ascending /*for example*/
select cv
protected void rptPriceRachiveBind()
{
using (MyEntities ctx = new MyEntities())
{
var catRef = Convert.ToInt32(Request.QueryString["CategoryRef"]);
var prodCounts = (
from A in ctx.Products
join B in ctx.ProductPrices
on A.ProductId equals B.ProductRef
where A.CategoryRef == catRef
group A by new { A.Name,B.ProductRef } into catGp
select
new
{
catGp.Key.ProductRef,
catGp.Key.Name,
proIdCount = catGp.Count()
}).ToList();
Repeater1.DataSource = prodCounts;
Repeater1.DataBind();
}